diff options
Diffstat (limited to 'sys/ofed/drivers/net/mlx4')
34 files changed, 0 insertions, 31637 deletions
diff --git a/sys/ofed/drivers/net/mlx4/Makefile b/sys/ofed/drivers/net/mlx4/Makefile deleted file mode 100644 index 05338e804fa2..000000000000 --- a/sys/ofed/drivers/net/mlx4/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# $FreeBSD$ -#.PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4:${.CURDIR}/../../ofed/include/linux -.PATH: ${.CURDIR}/../../../../../include/linux - -.include <src.opts.mk> - - -KMOD = mlx4 -SRCS = device_if.h bus_if.h pci_if.h vnode_if.h -SRCS+= alloc.c catas.c cmd.c cq.c eq.c fw.c icm.c intf.c main.c mcg.c mr.c linux_compat.c linux_radix.c -SRCS+= pd.c port.c profile.c qp.c reset.c sense.c srq.c resource_tracker.c sys_tune.c -SRCS+= opt_inet.h opt_inet6.h - - -#CFLAGS+= -I${.CURDIR}/../../ofed/drivers/net/mlx4 -#CFLAGS+= -I${.CURDIR}/../../ofed/include/ -CFLAGS+= -I${.CURDIR}/../../../../../include - -.if !defined(KERNBUILDDIR) -.if ${MK_INET_SUPPORT} != "no" -opt_inet.h: - @echo "#define INET 1" > ${.TARGET} -.endif - -.if ${MK_INET6_SUPPORT} != "no" -opt_inet6.h: - @echo "#define INET6 1" > ${.TARGET} -.endif -.endif - -.include <bsd.kmod.mk> - -CFLAGS+= -Wno-cast-qual -Wno-pointer-arith diff --git a/sys/ofed/drivers/net/mlx4/alloc.c b/sys/ofed/drivers/net/mlx4/alloc.c deleted file mode 100644 index da36b34d98b5..000000000000 --- a/sys/ofed/drivers/net/mlx4/alloc.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> - -#include "mlx4.h" - -u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) -{ - u32 obj; - - spin_lock(&bitmap->lock); - - obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last); - if (obj >= bitmap->max) { - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - obj = find_first_zero_bit(bitmap->table, bitmap->max); - } - - if (obj < bitmap->max) { - set_bit(obj, bitmap->table); - bitmap->last = (obj + 1); - if (bitmap->last == bitmap->max) - bitmap->last = 0; - obj |= bitmap->top; - } else - obj = -1; - - if (obj != -1) - --bitmap->avail; - - spin_unlock(&bitmap->lock); - - return obj; -} - -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr) -{ - mlx4_bitmap_free_range(bitmap, obj, 1, use_rr); -} - -static unsigned long find_aligned_range(unsigned long *bitmap, - u32 start, u32 nbits, - int len, int align, u32 skip_mask) -{ - unsigned long end, i; - -again: - start = ALIGN(start, align); - - while ((start < nbits) && (test_bit(start, bitmap) || - (start & skip_mask))) - start += align; - - if (start >= nbits) - return -1; - - end = start+len; - if (end > nbits) - return -1; - - for (i = start + 1; i < end; i++) { - if (test_bit(i, bitmap) || ((u32)i & skip_mask)) { - start = i + 1; - goto again; - } - } - - return start; -} - -u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, - int align, u32 skip_mask) -{ - u32 obj; - - if (likely(cnt == 1 && align == 1 && !skip_mask)) - return mlx4_bitmap_alloc(bitmap); - - spin_lock(&bitmap->lock); - - obj = find_aligned_range(bitmap->table, bitmap->last, - bitmap->max, cnt, align, skip_mask); - if (obj >= bitmap->max) { - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - obj = find_aligned_range(bitmap->table, 0, bitmap->max, - cnt, align, skip_mask); - } - - if (obj < bitmap->max) { - bitmap_set(bitmap->table, obj, cnt); - if (obj == bitmap->last) { - bitmap->last = (obj + cnt); - if (bitmap->last >= bitmap->max) - bitmap->last = 0; - } - obj |= bitmap->top; - } else - obj = -1; - - if (obj != -1) - bitmap->avail -= cnt; - - spin_unlock(&bitmap->lock); - - return obj; -} - -u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) -{ - return bitmap->avail; -} - -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, - int use_rr) -{ - obj &= bitmap->max + bitmap->reserved_top - 1; - - spin_lock(&bitmap->lock); - if (!use_rr) { - bitmap->last = min(bitmap->last, obj); - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - } - bitmap_clear(bitmap->table, obj, cnt); - bitmap->avail += cnt; - spin_unlock(&bitmap->lock); -} - -int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, - u32 reserved_bot, u32 reserved_top) -{ - /* sanity check */ - if (num <= (u64)reserved_top + reserved_bot) - return -EINVAL; - - /* num must be a power of 2 */ - if (num != roundup_pow_of_two(num)) - return -EINVAL; - - if (reserved_bot + reserved_top >= num) - return -EINVAL; - - bitmap->last = 0; - bitmap->top = 0; - bitmap->max = num - reserved_top; - bitmap->mask = mask; - bitmap->reserved_top = reserved_top; - bitmap->avail = num - reserved_top - reserved_bot; - spin_lock_init(&bitmap->lock); - bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * - sizeof (long), GFP_KERNEL); - if (!bitmap->table) - return -ENOMEM; - - bitmap_set(bitmap->table, 0, reserved_bot); - - return 0; -} - -void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap) -{ - kfree(bitmap->table); -} - -/* - * Handling for queue buffers -- we allocate a bunch of memory and - * register it in a memory region at HCA virtual address 0. If the - * requested size is > max_direct, we split the allocation into - * multiple pages, so we don't require too much contiguous memory. - */ - -int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, - struct mlx4_buf *buf) -{ - dma_addr_t t; - - if (size <= max_direct) { - buf->nbufs = 1; - buf->npages = 1; - buf->page_shift = get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, - size, &t, GFP_KERNEL); - if (!buf->direct.buf) - return -ENOMEM; - - buf->direct.map = t; - - while (t & ((1 << buf->page_shift) - 1)) { - --buf->page_shift; - buf->npages *= 2; - } - - memset(buf->direct.buf, 0, size); - } else { - int i; - - buf->direct.buf = NULL; - buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; - buf->npages = buf->nbufs; - buf->page_shift = PAGE_SHIFT; - buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), - GFP_KERNEL); - if (!buf->page_list) - return -ENOMEM; - - for (i = 0; i < buf->nbufs; ++i) { - buf->page_list[i].buf = - dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, - &t, GFP_KERNEL); - if (!buf->page_list[i].buf) - goto err_free; - - buf->page_list[i].map = t; - - memset(buf->page_list[i].buf, 0, PAGE_SIZE); - } - - if (BITS_PER_LONG == 64) { - struct page **pages; - pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); - if (!pages) - goto err_free; - for (i = 0; i < buf->nbufs; ++i) - pages[i] = virt_to_page(buf->page_list[i].buf); - buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); - kfree(pages); - if (!buf->direct.buf) - goto err_free; - } - } - - return 0; - -err_free: - mlx4_buf_free(dev, size, buf); - - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(mlx4_buf_alloc); - -void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) -{ - int i; - - if (buf->nbufs == 1) - dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, - buf->direct.map); - else { - if (BITS_PER_LONG == 64 && buf->direct.buf) - vunmap(buf->direct.buf); - - for (i = 0; i < buf->nbufs; ++i) - if (buf->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - buf->page_list[i].buf, - buf->page_list[i].map); - kfree(buf->page_list); - } -} -EXPORT_SYMBOL_GPL(mlx4_buf_free); - -static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) -{ - struct mlx4_db_pgdir *pgdir; - - pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); - if (!pgdir) - return NULL; - - bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2); - pgdir->bits[0] = pgdir->order0; - pgdir->bits[1] = pgdir->order1; - pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, - &pgdir->db_dma, GFP_KERNEL); - if (!pgdir->db_page) { - kfree(pgdir); - return NULL; - } - - return pgdir; -} - -static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, - struct mlx4_db *db, int order) -{ - int o; - int i; - - for (o = order; o <= 1; ++o) { - i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o); - if (i < MLX4_DB_PER_PAGE >> o) - goto found; - } - - return -ENOMEM; - -found: - clear_bit(i, pgdir->bits[o]); - - i <<= o; - - if (o > order) - set_bit(i ^ 1, pgdir->bits[order]); - - db->u.pgdir = pgdir; - db->index = i; - db->db = pgdir->db_page + db->index; - db->dma = pgdir->db_dma + db->index * 4; - db->order = order; - - return 0; -} - -int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_db_pgdir *pgdir; - int ret = 0; - - mutex_lock(&priv->pgdir_mutex); - - list_for_each_entry(pgdir, &priv->pgdir_list, list) - if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) - goto out; - - pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev)); - if (!pgdir) { - ret = -ENOMEM; - goto out; - } - - list_add(&pgdir->list, &priv->pgdir_list); - - /* This should never fail -- we just allocated an empty page: */ - WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order)); - -out: - mutex_unlock(&priv->pgdir_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_db_alloc); - -void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int o; - int i; - - mutex_lock(&priv->pgdir_mutex); - - o = db->order; - i = db->index; - - if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) { - clear_bit(i ^ 1, db->u.pgdir->order0); - ++o; - } - i >>= o; - set_bit(i, db->u.pgdir->bits[o]); - - if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - db->u.pgdir->db_page, db->u.pgdir->db_dma); - list_del(&db->u.pgdir->list); - kfree(db->u.pgdir); - } - - mutex_unlock(&priv->pgdir_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_db_free); - -int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, - int size, int max_direct) -{ - int err; - - err = mlx4_db_alloc(dev, &wqres->db, 1); - if (err) - return err; - - *wqres->db.db = 0; - - err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf); - if (err) - goto err_db; - - err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift, - &wqres->mtt); - if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf); - if (err) - goto err_mtt; - - return 0; - -err_mtt: - mlx4_mtt_cleanup(dev, &wqres->mtt); -err_buf: - mlx4_buf_free(dev, size, &wqres->buf); -err_db: - mlx4_db_free(dev, &wqres->db); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res); - -void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, - int size) -{ - mlx4_mtt_cleanup(dev, &wqres->mtt); - mlx4_buf_free(dev, size, &wqres->buf); - mlx4_db_free(dev, &wqres->db); -} -EXPORT_SYMBOL_GPL(mlx4_free_hwq_res); diff --git a/sys/ofed/drivers/net/mlx4/catas.c b/sys/ofed/drivers/net/mlx4/catas.c deleted file mode 100644 index 497e0ddb8956..000000000000 --- a/sys/ofed/drivers/net/mlx4/catas.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/workqueue.h> -#include <linux/module.h> - -#include <asm/byteorder.h> - -#include "mlx4.h" - -#define MLX4_CATAS_POLL_INTERVAL (5 * HZ) - -static DEFINE_SPINLOCK(catas_lock); - -static LIST_HEAD(catas_list); -static struct work_struct catas_work; - -static int internal_err_reset = 1; -module_param(internal_err_reset, int, 0644); -MODULE_PARM_DESC(internal_err_reset, - "Reset device on internal errors if non-zero" - " (default 1, in SRIOV mode default is 0)"); - -static void dump_err_buf(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - int i; - - mlx4_err(dev, "Internal error detected:\n"); - for (i = 0; i < priv->fw.catas_size; ++i) - mlx4_err(dev, " buf[%02x]: %08x\n", - i, swab32(readl(priv->catas_err.map + i))); -} - -static void poll_catas(unsigned long dev_ptr) -{ - struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (readl(priv->catas_err.map)) { - /* If the device is off-line, we cannot try to recover it */ - if (pci_channel_offline(dev->pdev)) - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); - else { - dump_err_buf(dev); - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); - - if (internal_err_reset) { - spin_lock(&catas_lock); - list_add(&priv->catas_err.list, &catas_list); - spin_unlock(&catas_lock); - - queue_work(mlx4_wq, &catas_work); - } - } - } else - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); -} - -static void catas_reset(struct work_struct *work) -{ - struct mlx4_priv *priv, *tmppriv; - struct mlx4_dev *dev; - - LIST_HEAD(tlist); - int ret; - - spin_lock_irq(&catas_lock); - list_splice_init(&catas_list, &tlist); - spin_unlock_irq(&catas_lock); - - list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { - struct pci_dev *pdev = priv->dev.pdev; - - /* If the device is off-line, we cannot reset it */ - if (pci_channel_offline(pdev)) - continue; - - ret = mlx4_restart_one(priv->dev.pdev); - /* 'priv' now is not valid */ - if (ret) - pr_err("mlx4 %s: Reset failed (%d)\n", - pci_name(pdev), ret); - else { - dev = pci_get_drvdata(pdev); - mlx4_dbg(dev, "Reset succeeded\n"); - } - } -} - -void mlx4_start_catas_poll(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - phys_addr_t addr; - - /*If we are in SRIOV the default of the module param must be 0*/ - if (mlx4_is_mfunc(dev)) - internal_err_reset = 0; - - INIT_LIST_HEAD(&priv->catas_err.list); - init_timer(&priv->catas_err.timer); - priv->catas_err.map = NULL; - - addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + - priv->fw.catas_offset; - - priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); - if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", - (unsigned long long) addr); - return; - } - - priv->catas_err.timer.data = (unsigned long) dev; - priv->catas_err.timer.function = poll_catas; - priv->catas_err.timer.expires = - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL); - add_timer(&priv->catas_err.timer); -} - -void mlx4_stop_catas_poll(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - del_timer_sync(&priv->catas_err.timer); - - if (priv->catas_err.map) { - iounmap(priv->catas_err.map); - priv->catas_err.map = NULL; - } - - spin_lock_irq(&catas_lock); - list_del_init(&priv->catas_err.list); - spin_unlock_irq(&catas_lock); -} - -void __init mlx4_catas_init(void) -{ - INIT_WORK(&catas_work, catas_reset); -} diff --git a/sys/ofed/drivers/net/mlx4/cmd.c b/sys/ofed/drivers/net/mlx4/cmd.c deleted file mode 100644 index 9d5177965162..000000000000 --- a/sys/ofed/drivers/net/mlx4/cmd.c +++ /dev/null @@ -1,2606 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/errno.h> - -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/device.h> -#include <linux/semaphore.h> -#include <rdma/ib_smi.h> - -#include <asm/io.h> -#include <linux/ktime.h> - -#include "mlx4.h" -#include "fw.h" - -#define CMD_POLL_TOKEN 0xffff -#define INBOX_MASK 0xffffffffffffff00ULL - -#define CMD_CHAN_VER 1 -#define CMD_CHAN_IF_REV 1 - -enum { - /* command completed successfully: */ - CMD_STAT_OK = 0x00, - /* Internal error (such as a bus error) occurred while processing command: */ - CMD_STAT_INTERNAL_ERR = 0x01, - /* Operation/command not supported or opcode modifier not supported: */ - CMD_STAT_BAD_OP = 0x02, - /* Parameter not supported or parameter out of range: */ - CMD_STAT_BAD_PARAM = 0x03, - /* System not enabled or bad system state: */ - CMD_STAT_BAD_SYS_STATE = 0x04, - /* Attempt to access reserved or unallocaterd resource: */ - CMD_STAT_BAD_RESOURCE = 0x05, - /* Requested resource is currently executing a command, or is otherwise busy: */ - CMD_STAT_RESOURCE_BUSY = 0x06, - /* Required capability exceeds device limits: */ - CMD_STAT_EXCEED_LIM = 0x08, - /* Resource is not in the appropriate state or ownership: */ - CMD_STAT_BAD_RES_STATE = 0x09, - /* Index out of range: */ - CMD_STAT_BAD_INDEX = 0x0a, - /* FW image corrupted: */ - CMD_STAT_BAD_NVMEM = 0x0b, - /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ - CMD_STAT_ICM_ERROR = 0x0c, - /* Attempt to modify a QP/EE which is not in the presumed state: */ - CMD_STAT_BAD_QP_STATE = 0x10, - /* Bad segment parameters (Address/Size): */ - CMD_STAT_BAD_SEG_PARAM = 0x20, - /* Memory Region has Memory Windows bound to: */ - CMD_STAT_REG_BOUND = 0x21, - /* HCA local attached memory not present: */ - CMD_STAT_LAM_NOT_PRE = 0x22, - /* Bad management packet (silently discarded): */ - CMD_STAT_BAD_PKT = 0x30, - /* More outstanding CQEs in CQ than new CQ size: */ - CMD_STAT_BAD_SIZE = 0x40, - /* Multi Function device support required: */ - CMD_STAT_MULTI_FUNC_REQ = 0x50, -}; - -enum { - HCR_IN_PARAM_OFFSET = 0x00, - HCR_IN_MODIFIER_OFFSET = 0x08, - HCR_OUT_PARAM_OFFSET = 0x0c, - HCR_TOKEN_OFFSET = 0x14, - HCR_STATUS_OFFSET = 0x18, - - HCR_OPMOD_SHIFT = 12, - HCR_T_BIT = 21, - HCR_E_BIT = 22, - HCR_GO_BIT = 23 -}; - -enum { - GO_BIT_TIMEOUT_MSECS = 10000 -}; - -enum mlx4_vlan_transition { - MLX4_VLAN_TRANSITION_VST_VST = 0, - MLX4_VLAN_TRANSITION_VST_VGT = 1, - MLX4_VLAN_TRANSITION_VGT_VST = 2, - MLX4_VLAN_TRANSITION_VGT_VGT = 3, -}; - - -struct mlx4_cmd_context { - struct completion done; - int result; - int next; - u64 out_param; - u16 token; - u8 fw_status; -}; - -static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr_cmd *in_vhcr); - -static int mlx4_status_to_errno(u8 status) -{ - static const int trans_table[] = { - [CMD_STAT_INTERNAL_ERR] = -EIO, - [CMD_STAT_BAD_OP] = -EPERM, - [CMD_STAT_BAD_PARAM] = -EINVAL, - [CMD_STAT_BAD_SYS_STATE] = -ENXIO, - [CMD_STAT_BAD_RESOURCE] = -EBADF, - [CMD_STAT_RESOURCE_BUSY] = -EBUSY, - [CMD_STAT_EXCEED_LIM] = -ENOMEM, - [CMD_STAT_BAD_RES_STATE] = -EBADF, - [CMD_STAT_BAD_INDEX] = -EBADF, - [CMD_STAT_BAD_NVMEM] = -EFAULT, - [CMD_STAT_ICM_ERROR] = -ENFILE, - [CMD_STAT_BAD_QP_STATE] = -EINVAL, - [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, - [CMD_STAT_REG_BOUND] = -EBUSY, - [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, - [CMD_STAT_BAD_PKT] = -EINVAL, - [CMD_STAT_BAD_SIZE] = -ENOMEM, - [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, - }; - - if (status >= ARRAY_SIZE(trans_table) || - (status != CMD_STAT_OK && trans_table[status] == 0)) - return -EIO; - - return trans_table[status]; -} - -static const char *cmd_to_str(u16 cmd) -{ - switch (cmd) { - case MLX4_CMD_SYS_EN: return "SYS_EN"; - case MLX4_CMD_SYS_DIS: return "SYS_DIS"; - case MLX4_CMD_MAP_FA: return "MAP_FA"; - case MLX4_CMD_UNMAP_FA: return "UNMAP_FA"; - case MLX4_CMD_RUN_FW: return "RUN_FW"; - case MLX4_CMD_MOD_STAT_CFG: return "MOD_STAT_CFG"; - case MLX4_CMD_QUERY_DEV_CAP: return "QUERY_DEV_CAP"; - case MLX4_CMD_QUERY_FW: return "QUERY_FW"; - case MLX4_CMD_ENABLE_LAM: return "ENABLE_LAM"; - case MLX4_CMD_DISABLE_LAM: return "DISABLE_LAM"; - case MLX4_CMD_QUERY_DDR: return "QUERY_DDR"; - case MLX4_CMD_QUERY_ADAPTER: return "QUERY_ADAPTER"; - case MLX4_CMD_INIT_HCA: return "INIT_HCA"; - case MLX4_CMD_CLOSE_HCA: return "CLOSE_HCA"; - case MLX4_CMD_INIT_PORT: return "INIT_PORT"; - case MLX4_CMD_CLOSE_PORT: return "CLOSE_PORT"; - case MLX4_CMD_QUERY_HCA: return "QUERY_HCA"; - case MLX4_CMD_QUERY_PORT: return "QUERY_PORT"; - case MLX4_CMD_SENSE_PORT: return "SENSE_PORT"; - case MLX4_CMD_HW_HEALTH_CHECK: return "HW_HEALTH_CHECK"; - case MLX4_CMD_SET_PORT: return "SET_PORT"; - case MLX4_CMD_SET_NODE: return "SET_NODE"; - case MLX4_CMD_QUERY_FUNC: return "QUERY_FUNC"; - case MLX4_CMD_MAP_ICM: return "MAP_ICM"; - case MLX4_CMD_UNMAP_ICM: return "UNMAP_ICM"; - case MLX4_CMD_MAP_ICM_AUX: return "MAP_ICM_AUX"; - case MLX4_CMD_UNMAP_ICM_AUX: return "UNMAP_ICM_AUX"; - case MLX4_CMD_SET_ICM_SIZE: return "SET_ICM_SIZE"; - /*master notify fw on finish for slave's flr*/ - case MLX4_CMD_INFORM_FLR_DONE: return "INFORM_FLR_DONE"; - case MLX4_CMD_GET_OP_REQ: return "GET_OP_REQ"; - - /* TPT commands */ - case MLX4_CMD_SW2HW_MPT: return "SW2HW_MPT"; - case MLX4_CMD_QUERY_MPT: return "QUERY_MPT"; - case MLX4_CMD_HW2SW_MPT: return "HW2SW_MPT"; - case MLX4_CMD_READ_MTT: return "READ_MTT"; - case MLX4_CMD_WRITE_MTT: return "WRITE_MTT"; - case MLX4_CMD_SYNC_TPT: return "SYNC_TPT"; - - /* EQ commands */ - case MLX4_CMD_MAP_EQ: return "MAP_EQ"; - case MLX4_CMD_SW2HW_EQ: return "SW2HW_EQ"; - case MLX4_CMD_HW2SW_EQ: return "HW2SW_EQ"; - case MLX4_CMD_QUERY_EQ: return "QUERY_EQ"; - - /* CQ commands */ - case MLX4_CMD_SW2HW_CQ: return "SW2HW_CQ"; - case MLX4_CMD_HW2SW_CQ: return "HW2SW_CQ"; - case MLX4_CMD_QUERY_CQ: return "QUERY_CQ:"; - case MLX4_CMD_MODIFY_CQ: return "MODIFY_CQ:"; - - /* SRQ commands */ - case MLX4_CMD_SW2HW_SRQ: return "SW2HW_SRQ"; - case MLX4_CMD_HW2SW_SRQ: return "HW2SW_SRQ"; - case MLX4_CMD_QUERY_SRQ: return "QUERY_SRQ"; - case MLX4_CMD_ARM_SRQ: return "ARM_SRQ"; - - /* QP/EE commands */ - case MLX4_CMD_RST2INIT_QP: return "RST2INIT_QP"; - case MLX4_CMD_INIT2RTR_QP: return "INIT2RTR_QP"; - case MLX4_CMD_RTR2RTS_QP: return "RTR2RTS_QP"; - case MLX4_CMD_RTS2RTS_QP: return "RTS2RTS_QP"; - case MLX4_CMD_SQERR2RTS_QP: return "SQERR2RTS_QP"; - case MLX4_CMD_2ERR_QP: return "2ERR_QP"; - case MLX4_CMD_RTS2SQD_QP: return "RTS2SQD_QP"; - case MLX4_CMD_SQD2SQD_QP: return "SQD2SQD_QP"; - case MLX4_CMD_SQD2RTS_QP: return "SQD2RTS_QP"; - case MLX4_CMD_2RST_QP: return "2RST_QP"; - case MLX4_CMD_QUERY_QP: return "QUERY_QP"; - case MLX4_CMD_INIT2INIT_QP: return "INIT2INIT_QP"; - case MLX4_CMD_SUSPEND_QP: return "SUSPEND_QP"; - case MLX4_CMD_UNSUSPEND_QP: return "UNSUSPEND_QP"; - /* special QP and management commands */ - case MLX4_CMD_CONF_SPECIAL_QP: return "CONF_SPECIAL_QP"; - case MLX4_CMD_MAD_IFC: return "MAD_IFC"; - - /* multicast commands */ - case MLX4_CMD_READ_MCG: return "READ_MCG"; - case MLX4_CMD_WRITE_MCG: return "WRITE_MCG"; - case MLX4_CMD_MGID_HASH: return "MGID_HASH"; - - /* miscellaneous commands */ - case MLX4_CMD_DIAG_RPRT: return "DIAG_RPRT"; - case MLX4_CMD_NOP: return "NOP"; - case MLX4_CMD_ACCESS_MEM: return "ACCESS_MEM"; - case MLX4_CMD_SET_VEP: return "SET_VEP"; - - /* Ethernet specific commands */ - case MLX4_CMD_SET_VLAN_FLTR: return "SET_VLAN_FLTR"; - case MLX4_CMD_SET_MCAST_FLTR: return "SET_MCAST_FLTR"; - case MLX4_CMD_DUMP_ETH_STATS: return "DUMP_ETH_STATS"; - - /* Communication channel commands */ - case MLX4_CMD_ARM_COMM_CHANNEL: return "ARM_COMM_CHANNEL"; - case MLX4_CMD_GEN_EQE: return "GEN_EQE"; - - /* virtual commands */ - case MLX4_CMD_ALLOC_RES: return "ALLOC_RES"; - case MLX4_CMD_FREE_RES: return "FREE_RES"; - case MLX4_CMD_MCAST_ATTACH: return "MCAST_ATTACH"; - case MLX4_CMD_UCAST_ATTACH: return "UCAST_ATTACH"; - case MLX4_CMD_PROMISC: return "PROMISC"; - case MLX4_CMD_QUERY_FUNC_CAP: return "QUERY_FUNC_CAP"; - case MLX4_CMD_QP_ATTACH: return "QP_ATTACH"; - - /* debug commands */ - case MLX4_CMD_QUERY_DEBUG_MSG: return "QUERY_DEBUG_MSG"; - case MLX4_CMD_SET_DEBUG_MSG: return "SET_DEBUG_MSG"; - - /* statistics commands */ - case MLX4_CMD_QUERY_IF_STAT: return "QUERY_IF_STAT"; - case MLX4_CMD_SET_IF_STAT: return "SET_IF_STAT"; - - /* register/delete flow steering network rules */ - case MLX4_QP_FLOW_STEERING_ATTACH: return "QP_FLOW_STEERING_ATTACH"; - case MLX4_QP_FLOW_STEERING_DETACH: return "QP_FLOW_STEERING_DETACH"; - case MLX4_FLOW_STEERING_IB_UC_QP_RANGE: return "FLOW_STEERING_IB_UC_QP_RANGE"; - default: return "OTHER"; - } -} - -static u8 mlx4_errno_to_status(int errno) -{ - switch (errno) { - case -EPERM: - return CMD_STAT_BAD_OP; - case -EINVAL: - return CMD_STAT_BAD_PARAM; - case -ENXIO: - return CMD_STAT_BAD_SYS_STATE; - case -EBUSY: - return CMD_STAT_RESOURCE_BUSY; - case -ENOMEM: - return CMD_STAT_EXCEED_LIM; - case -ENFILE: - return CMD_STAT_ICM_ERROR; - default: - return CMD_STAT_INTERNAL_ERR; - } -} - -static int comm_pending(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u32 status = readl(&priv->mfunc.comm->slave_read); - - return (swab32(status) >> 31) != priv->cmd.comm_toggle; -} - -static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u32 val; - - priv->cmd.comm_toggle ^= 1; - val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); - __raw_writel((__force u32) cpu_to_be32(val), - &priv->mfunc.comm->slave_write); - mmiowb(); -} - -static 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; - int ret_from_pending = 0; - - /* First, verify that the master reports correct status */ - if (comm_pending(dev)) { - mlx4_warn(dev, "Communication channel is not idle." - "my toggle is %d (cmd:0x%x)\n", - priv->cmd.comm_toggle, cmd); - 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)) - cond_resched(); - ret_from_pending = comm_pending(dev); - if (ret_from_pending) { - /* check if the slave is trying to boot in the middle of - * FLR process. The only non-zero result in the RESET command - * is MLX4_DELAY_RESET_SLAVE*/ - if ((MLX4_COMM_CMD_RESET == cmd)) { - mlx4_warn(dev, "Got slave FLRed from Communication" - " channel (ret:0x%x)\n", ret_from_pending); - err = MLX4_DELAY_RESET_SLAVE; - } else { - mlx4_warn(dev, "Communication channel timed out\n"); - err = -ETIMEDOUT; - } - } - - up(&priv->cmd.poll_sem); - return err; -} - -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; - unsigned long end; - int err = 0; - - down(&cmd->event_sem); - - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); - if (comm_pending(dev)) { - mlx4_warn(dev, "mlx4_comm_cmd_wait: Comm channel " - "is not idle. My toggle is %d (op: 0x%x)\n", - mlx4_priv(dev)->cmd.comm_toggle, op); - up(&cmd->event_sem); - return -EAGAIN; - } - - 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); - - /* In slave, wait unconditionally for completion */ - wait_for_completion(&context->done); - - err = context->result; - if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { - mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", - op, context->fw_status); - goto out; - } - -out: - /* wait for comm channel ready - * this is necessary for prevention the race - * when switching between event to polling mode - */ - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); - - 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; - - if (pci_channel_offline(dev->pdev)) - return -EIO; - - status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); - - return (status & swab32(1 << HCR_GO_BIT)) || - (mlx4_priv(dev)->cmd.toggle == - !!(status & swab32(1 << HCR_T_BIT))); -} - -static int get_status(struct mlx4_dev *dev, u32 *status, int *go_bit, - int *t_bit) -{ - if (pci_channel_offline(dev->pdev)) - return -EIO; - - *status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); - *t_bit = !!(*status & swab32(1 << HCR_T_BIT)); - *go_bit = !!(*status & swab32(1 << HCR_GO_BIT)); - - return 0; -} - -static int mlx4_cmd_post(struct mlx4_dev *dev, struct timespec *ts1, - u64 in_param, u64 out_param, u32 in_modifier, - u8 op_modifier, u16 op, u16 token, int event) -{ - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - u32 __iomem *hcr = cmd->hcr; - int ret = -EAGAIN; - unsigned long end; - int err, go_bit = 0, t_bit = 0; - u32 status = 0; - - mutex_lock(&cmd->hcr_mutex); - - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - ret = -EIO; - goto out; - } - - end = jiffies; - if (event) - end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); - - while (cmd_pending(dev)) { - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - ret = -EIO; - goto out; - } - - if (time_after_eq(jiffies, end)) { - mlx4_err(dev, "%s:cmd_pending failed\n", __func__); - goto out; - } - cond_resched(); - } - - /* - * We use writel (instead of something like memcpy_toio) - * because writes of less than 32 bits to the HCR don't work - * (and some architectures such as ia64 implement memcpy_toio - * in terms of writeb). - */ - __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); - __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); - __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); - __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); - __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); - __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); - - if (ts1) - ktime_get_ts(ts1); - - /* __raw_writel may not order writes. */ - wmb(); - - __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | - (cmd->toggle << HCR_T_BIT) | - (event ? (1 << HCR_E_BIT) : 0) | - (op_modifier << HCR_OPMOD_SHIFT) | - op), hcr + 6); - - /* - * Make sure that our HCR writes don't get mixed in with - * writes from another CPU starting a FW command. - */ - mmiowb(); - - cmd->toggle = cmd->toggle ^ 1; - - ret = 0; - -out: - if (ret) { - err = get_status(dev, &status, &go_bit, &t_bit); - mlx4_warn(dev, "Could not post command %s (0x%x): ret=%d, " - "in_param=0x%llx, in_mod=0x%x, op_mod=0x%x, " - "get_status err=%d, status_reg=0x%x, go_bit=%d, " - "t_bit=%d, toggle=0x%x\n", cmd_to_str(op), op, ret, - (unsigned long long) in_param, in_modifier, op_modifier, err, status, - go_bit, t_bit, cmd->toggle); - } - mutex_unlock(&cmd->hcr_mutex); - return ret; -} - -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_cmd *vhcr = priv->mfunc.vhcr; - int ret; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - - vhcr->in_param = cpu_to_be64(in_param); - vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; - vhcr->in_modifier = cpu_to_be32(in_modifier); - vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); - vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); - vhcr->status = 0; - vhcr->flags = !!(priv->cmd.use_events) << 6; - - if (mlx4_is_master(dev)) { - ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); - if (!ret) { - if (out_is_imm) { - if (out_param) - *out_param = - be64_to_cpu(vhcr->out_param); - else { - mlx4_err(dev, "response expected while" - "output mailbox is NULL for " - "command 0x%x\n", op); - vhcr->status = CMD_STAT_BAD_PARAM; - } - } - ret = mlx4_status_to_errno(vhcr->status); - } - } else { - ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, - MLX4_COMM_TIME + timeout); - if (!ret) { - if (out_is_imm) { - if (out_param) - *out_param = - be64_to_cpu(vhcr->out_param); - else { - mlx4_err(dev, "response expected while" - "output mailbox is NULL for " - "command 0x%x\n", op); - vhcr->status = CMD_STAT_BAD_PARAM; - } - } - ret = mlx4_status_to_errno(vhcr->status); - } else - mlx4_err(dev, "failed execution of VHCR_POST command" - "opcode %s (0x%x)\n", cmd_to_str(op), op); - } - - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return ret; -} - -static int mlx4_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) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - void __iomem *hcr = priv->cmd.hcr; - int err = 0; - unsigned long end; - u32 stat; - - down(&priv->cmd.poll_sem); - - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - err = -EIO; - goto out; - } - - err = mlx4_cmd_post(dev, NULL, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); - if (err) - goto out; - - end = msecs_to_jiffies(timeout) + jiffies; - while (cmd_pending(dev) && time_before(jiffies, end)) { - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - err = -EIO; - goto out; - } - - cond_resched(); - } - - if (cmd_pending(dev)) { - mlx4_warn(dev, "command %s (0x%x) timed out (go bit not cleared)\n", - cmd_to_str(op), op); - err = -ETIMEDOUT; - goto out; - } - - if (out_is_imm) - *out_param = - (u64) be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | - (u64) be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); - stat = be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; - err = mlx4_status_to_errno(stat); - if (err) - mlx4_err(dev, "command %s (0x%x) failed: fw status = 0x%x\n", - cmd_to_str(op), op, stat); - -out: - up(&priv->cmd.poll_sem); - return err; -} - -void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_context *context = - &priv->cmd.context[token & priv->cmd.token_mask]; - - /* previously timed out command completing at long last */ - if (token != context->token) - return; - - context->fw_status = status; - context->result = mlx4_status_to_errno(status); - context->out_param = out_param; - - complete(&context->done); -} - -static int mlx4_cmd_wait(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_cmd *cmd = &mlx4_priv(dev)->cmd; - struct mlx4_cmd_context *context; - int err = 0; - int go_bit = 0, t_bit = 0, stat_err; - u32 status = 0; - struct timespec ts1, ts2; - ktime_t t1, t2, delta; - s64 ds; - - if (out_is_imm && !out_param) - return -EINVAL; - - 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); - - err = mlx4_cmd_post(dev, &ts1, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, context->token, 1); - if (err) - goto out; - - if (!wait_for_completion_timeout(&context->done, - msecs_to_jiffies(timeout))) { - stat_err = get_status(dev, &status, &go_bit, &t_bit); - mlx4_warn(dev, "command %s (0x%x) timed out: in_param=0x%llx, " - "in_mod=0x%x, op_mod=0x%x, get_status err=%d, " - "status_reg=0x%x, go_bit=%d, t_bit=%d, toggle=0x%x\n" - , cmd_to_str(op), op, (unsigned long long) in_param, in_modifier, - op_modifier, stat_err, status, go_bit, t_bit, - mlx4_priv(dev)->cmd.toggle); - err = -EBUSY; - goto out; - } - if (mlx4_debug_level & MLX4_DEBUG_MASK_CMD_TIME) { - ktime_get_ts(&ts2); - t1 = timespec_to_ktime(ts1); - t2 = timespec_to_ktime(ts2); - delta = ktime_sub(t2, t1); - ds = ktime_to_ns(delta); - pr_info("mlx4: fw exec time for %s is %lld nsec\n", cmd_to_str(op), (long long) ds); - } - - err = context->result; - if (err) { - mlx4_err(dev, "command %s (0x%x) failed: in_param=0x%llx, " - "in_mod=0x%x, op_mod=0x%x, fw status = 0x%x\n", - cmd_to_str(op), op, (unsigned long long) in_param, in_modifier, - op_modifier, context->fw_status); - - switch(context->fw_status) { - case CMD_STAT_BAD_PARAM: - mlx4_err(dev, "Parameter is not supported, " - "parameter is out of range\n"); - break; - case CMD_STAT_EXCEED_LIM: - mlx4_err(dev, "Required capability exceeded " - "device limits\n"); - break; - default: - break; - } - goto out; - } - - if (out_is_imm) - *out_param = context->out_param; - -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_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, int native) -{ - if (pci_channel_offline(dev->pdev)) - return -EIO; - - if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { - 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); - else - return mlx4_cmd_poll(dev, in_param, out_param, - out_is_imm, in_modifier, - op_modifier, op, timeout); - } - return mlx4_slave_cmd(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, MLX4_CMD_NATIVE); -} - -static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, - int slave, u64 slave_addr, - int size, int is_read) -{ - u64 in_param; - u64 out_param; - - if ((slave_addr & 0xfff) | (master_addr & 0xfff) | - (slave & ~0x7f) | (size & 0xff)) { - mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx " - "master_addr:0x%llx slave_id:%d size:%d\n", - (unsigned long long) slave_addr, (unsigned long long) master_addr, slave, size); - return -EINVAL; - } - - if (is_read) { - in_param = (u64) slave | slave_addr; - out_param = (u64) dev->caps.function | master_addr; - } else { - in_param = (u64) dev->caps.function | master_addr; - out_param = (u64) slave | slave_addr; - } - - return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, - MLX4_CMD_ACCESS_MEM, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox) -{ - struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf); - struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf); - int err; - int i; - - if (index & 0x1f) - return -EINVAL; - - in_mad->attr_mod = cpu_to_be32(index / 32); - - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (err) - return err; - - for (i = 0; i < 32; ++i) - pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]); - - return err; -} - -static int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox) -{ - int i; - int err; - - for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) { - err = query_pkey_block(dev, port, i, table + i, inbox, outbox); - if (err) - return err; - } - - return 0; -} -#define PORT_CAPABILITY_LOCATION_IN_SMP 20 -#define PORT_STATE_OFFSET 32 - -static enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf) -{ - if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP) - return IB_PORT_ACTIVE; - else - return IB_PORT_DOWN; -} - -static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct ib_smp *smp = inbox->buf; - u32 index; - u8 port; - u16 *table; - int err; - int vidx, pidx; - struct mlx4_priv *priv = mlx4_priv(dev); - struct ib_smp *outsmp = outbox->buf; - __be16 *outtab = (__be16 *)(outsmp->data); - __be32 slave_cap_mask; - __be64 slave_node_guid; - port = vhcr->in_modifier; - - if (smp->base_version == 1 && - smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && - smp->class_version == 1) { - if (smp->method == IB_MGMT_METHOD_GET) { - if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { - index = be32_to_cpu(smp->attr_mod); - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL); - if (!table) - return -ENOMEM; - /* need to get the full pkey table because the paravirtualized - * pkeys may be scattered among several pkey blocks. - */ - err = get_full_pkey_table(dev, port, table, inbox, outbox); - if (!err) { - for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) { - pidx = priv->virt2phys_pkey[slave][port - 1][vidx]; - outtab[vidx % 32] = cpu_to_be16(table[pidx]); - } - } - kfree(table); - return err; - } - if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) { - /*get the slave specific caps:*/ - /*do the command */ - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - /* modify the response for slaves */ - if (!err && slave != mlx4_master_func_num(dev)) { - u8 *state = outsmp->data + PORT_STATE_OFFSET; - - *state = (*state & 0xf0) | vf_port_state(dev, port, slave); - slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; - memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4); - } - return err; - } - if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) { - /* compute slave's gid block */ - smp->attr_mod = cpu_to_be32(slave / 8); - /* execute cmd */ - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (!err) { - /* if needed, move slave gid to index 0 */ - if (slave % 8) - memcpy(outsmp->data, - outsmp->data + (slave % 8) * 8, 8); - /* delete all other gids */ - memset(outsmp->data + 8, 0, 56); - } - return err; - } - if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (!err) { - slave_node_guid = mlx4_get_slave_node_guid(dev, slave); - memcpy(outsmp->data + 12, &slave_node_guid, 8); - } - return err; - } - } - } - if (slave != mlx4_master_func_num(dev) && - ((smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) || - (smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && - smp->method == IB_MGMT_METHOD_SET))) { - mlx4_err(dev, "slave %d is trying to execute a Subnet MGMT MAD, " - "class 0x%x, method 0x%x for attr 0x%x. Rejecting\n", - slave, smp->method, smp->mgmt_class, - be16_to_cpu(smp->attr_id)); - return -EPERM; - } - /*default:*/ - return mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); -} - -static int MLX4_CMD_DIAG_RPRT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -static int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u64 in_param; - u64 out_param; - int err; - - in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; - out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; - if (cmd->encode_slave_id) { - in_param &= 0xffffffffffffff00ll; - in_param |= slave; - } - - err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, - vhcr->in_modifier, vhcr->op_modifier, vhcr->op, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - if (cmd->out_is_imm) - vhcr->out_param = out_param; - - return err; -} - -static struct mlx4_cmd_info cmd_info[] = { - { - .opcode = MLX4_CMD_QUERY_FW, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_FW_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_HCA, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_QUERY_DEV_CAP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_DEV_CAP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_FUNC_CAP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_FUNC_CAP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_ADAPTER, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_INIT_PORT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT_PORT_wrapper - }, - { - .opcode = MLX4_CMD_CLOSE_PORT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_CLOSE_PORT_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_PORT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_PORT_wrapper - }, - { - .opcode = MLX4_CMD_SET_PORT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_PORT_wrapper - }, - { - .opcode = MLX4_CMD_MAP_EQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MAP_EQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_EQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_EQ_wrapper - }, - { - .opcode = MLX4_CMD_HW_HEALTH_CHECK, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_DIAG_RPRT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = MLX4_CMD_DIAG_RPRT_wrapper - }, - { - .opcode = MLX4_CMD_NOP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_ALLOC_RES, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_ALLOC_RES_wrapper - }, - { - .opcode = MLX4_CMD_FREE_RES, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_FREE_RES_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_MPT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_MPT_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_MPT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_MPT_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_MPT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_MPT_wrapper - }, - { - .opcode = MLX4_CMD_READ_MTT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_WRITE_MTT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_WRITE_MTT_wrapper - }, - { - .opcode = MLX4_CMD_SYNC_TPT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_HW2SW_EQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_HW2SW_EQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_EQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_QUERY_EQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_CQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_CQ_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_CQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_CQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_CQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_CQ_wrapper - }, - { - .opcode = MLX4_CMD_MODIFY_CQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MODIFY_CQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_SRQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_SRQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_SRQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_ARM_SRQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_ARM_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_RST2INIT_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_RST2INIT_QP_wrapper - }, - { - .opcode = MLX4_CMD_INIT2INIT_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT2INIT_QP_wrapper - }, - { - .opcode = MLX4_CMD_INIT2RTR_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT2RTR_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTR2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_RTR2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTS2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_RTS2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQERR2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQERR2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_2ERR_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTS2SQD_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQD2SQD_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQD2SQD_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQD2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQD2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_2RST_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_2RST_QP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_QP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_SUSPEND_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_UNSUSPEND_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_UPDATE_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = MLX4_CMD_UPDATE_QP_wrapper - }, - { - .opcode = MLX4_CMD_CONF_SPECIAL_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, /* XXX verify: only demux can do this */ - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_MAD_IFC, - .has_inbox = true, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MAD_IFC_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_IF_STAT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_IF_STAT_wrapper - }, - /* Native multicast commands are not available for guests */ - { - .opcode = MLX4_CMD_QP_ATTACH, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_ATTACH_wrapper - }, - { - .opcode = MLX4_CMD_PROMISC, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_PROMISC_wrapper - }, - /* Ethernet specific commands */ - { - .opcode = MLX4_CMD_SET_VLAN_FLTR, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_VLAN_FLTR_wrapper - }, - { - .opcode = MLX4_CMD_SET_MCAST_FLTR, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_MCAST_FLTR_wrapper - }, - { - .opcode = MLX4_CMD_DUMP_ETH_STATS, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_DUMP_ETH_STATS_wrapper - }, - { - .opcode = MLX4_CMD_INFORM_FLR_DONE, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - /* flow steering commands */ - { - .opcode = MLX4_QP_FLOW_STEERING_ATTACH, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper - }, - { - .opcode = MLX4_QP_FLOW_STEERING_DETACH, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper - }, - /* wol commands */ - { - .opcode = MLX4_CMD_MOD_STAT_CFG, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = mlx4_MOD_STAT_CFG_wrapper - }, -}; - -static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr_cmd *in_vhcr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_info *cmd = NULL; - struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; - struct mlx4_vhcr *vhcr; - struct mlx4_cmd_mailbox *inbox = NULL; - struct mlx4_cmd_mailbox *outbox = NULL; - u64 in_param; - u64 out_param; - int ret = 0; - int i; - int err = 0; - - /* Create sw representation of Virtual HCR */ - vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); - if (!vhcr) - return -ENOMEM; - - /* DMA in the vHCR */ - if (!in_vhcr) { - ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, - priv->mfunc.master.slave_state[slave].vhcr_dma, - ALIGN(sizeof(struct mlx4_vhcr_cmd), - MLX4_ACCESS_MEM_ALIGN), 1); - if (ret) { - mlx4_err(dev, "%s:Failed reading vhcr" - "ret: 0x%x\n", __func__, ret); - kfree(vhcr); - return ret; - } - } - - /* Fill SW VHCR fields */ - vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); - vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); - vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); - vhcr->token = be16_to_cpu(vhcr_cmd->token); - vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; - vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); - vhcr->e_bit = vhcr_cmd->flags & (1 << 6); - - /* Lookup command */ - for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { - if (vhcr->op == cmd_info[i].opcode) { - cmd = &cmd_info[i]; - break; - } - } - if (!cmd) { - mlx4_err(dev, "unparavirt command: %s (0x%x) accepted from slave:%d\n", - cmd_to_str(vhcr->op), vhcr->op, slave); - vhcr_cmd->status = CMD_STAT_BAD_PARAM; - goto out_status; - } - - /* Read inbox */ - if (cmd->has_inbox) { - vhcr->in_param &= INBOX_MASK; - inbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inbox)) { - vhcr_cmd->status = CMD_STAT_BAD_SIZE; - inbox = NULL; - goto out_status; - } - - if (mlx4_ACCESS_MEM(dev, inbox->dma, slave, - vhcr->in_param, - MLX4_MAILBOX_SIZE, 1)) { - mlx4_err(dev, "%s: Failed reading inbox for cmd %s (0x%x)\n", - __func__, cmd_to_str(cmd->opcode), cmd->opcode); - vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; - goto out_status; - } - } - - /* Apply permission and bound checks if applicable */ - if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { - mlx4_warn(dev, "Command %s (0x%x) from slave: %d failed protection " - "checks for resource_id: %d\n", cmd_to_str(vhcr->op), - vhcr->op, slave, vhcr->in_modifier); - vhcr_cmd->status = CMD_STAT_BAD_OP; - goto out_status; - } - - /* Allocate outbox */ - if (cmd->has_outbox) { - outbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outbox)) { - vhcr_cmd->status = CMD_STAT_BAD_SIZE; - outbox = NULL; - goto out_status; - } - } - - /* Execute the command! */ - if (cmd->wrapper) { - err = cmd->wrapper(dev, slave, vhcr, inbox, outbox, - cmd); - if (cmd->out_is_imm) - vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); - } else { - in_param = cmd->has_inbox ? (u64) inbox->dma : - vhcr->in_param; - out_param = cmd->has_outbox ? (u64) outbox->dma : - vhcr->out_param; - err = __mlx4_cmd(dev, in_param, &out_param, - cmd->out_is_imm, vhcr->in_modifier, - vhcr->op_modifier, vhcr->op, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - if (cmd->out_is_imm) { - vhcr->out_param = out_param; - vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); - } - } - - if (err) { - if (!cmd->skip_err_print) - mlx4_warn(dev, "vhcr command %s (0x%x) slave:%d " - "in_param 0x%llx in_mod=0x%x, op_mod=0x%x " - "failed with error:%d, status %d\n", - cmd_to_str(vhcr->op), vhcr->op, slave, - (unsigned long long) vhcr->in_param, vhcr->in_modifier, - vhcr->op_modifier, vhcr->errno, err); - vhcr_cmd->status = mlx4_errno_to_status(err); - goto out_status; - } - - - /* Write outbox if command completed successfully */ - if (cmd->has_outbox && !vhcr_cmd->status) { - ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, - vhcr->out_param, - MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); - if (ret) { - /* If we failed to write back the outbox after the - *command was successfully executed, we must fail this - * slave, as it is now in undefined state */ - mlx4_err(dev, "%s: Failed writing outbox\n", __func__); - goto out; - } - } - -out_status: - /* DMA back vhcr result */ - if (!in_vhcr) { - ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, - priv->mfunc.master.slave_state[slave].vhcr_dma, - ALIGN(sizeof(struct mlx4_vhcr), - MLX4_ACCESS_MEM_ALIGN), - MLX4_CMD_WRAPPED); - if (ret) - mlx4_err(dev, "%s:Failed writing vhcr result\n", - __func__); - else if (vhcr->e_bit && - mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) - mlx4_warn(dev, "Failed to generate command completion " - "eqe for slave %d\n", slave); - } - -out: - kfree(vhcr); - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_free_cmd_mailbox(dev, outbox); - return ret; -} - -static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, - int slave, int port) -{ - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_vport_state *vp_admin; - struct mlx4_vf_immed_vlan_work *work; - int err; - int admin_vlan_ix = NO_INDX; - - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - - if (vp_oper->state.default_vlan == vp_admin->default_vlan && - vp_oper->state.default_qos == vp_admin->default_qos) - return 0; - - work = kzalloc(sizeof(*work), GFP_KERNEL); - if (!work) - return -ENOMEM; - - if (vp_oper->state.default_vlan != vp_admin->default_vlan) { - if (MLX4_VGT != vp_admin->default_vlan) { - err = __mlx4_register_vlan(&priv->dev, port, - vp_admin->default_vlan, - &admin_vlan_ix); - if (err) { - mlx4_warn((&priv->dev), - "No vlan resources slave %d, port %d\n", - slave, port); - kfree(work); - return err; - } - } else { - admin_vlan_ix = NO_INDX; - } - work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; - mlx4_dbg((&(priv->dev)), - "alloc vlan %d idx %d slave %d port %d\n", - (int)(vp_admin->default_vlan), - admin_vlan_ix, slave, port); - } - - /* save original vlan ix and vlan id */ - work->orig_vlan_id = vp_oper->state.default_vlan; - work->orig_vlan_ix = vp_oper->vlan_idx; - - /* handle new qos */ - if (vp_oper->state.default_qos != vp_admin->default_qos) - work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; - - if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) - vp_oper->vlan_idx = admin_vlan_ix; - - vp_oper->state.default_vlan = vp_admin->default_vlan; - vp_oper->state.default_qos = vp_admin->default_qos; - - /* iterate over QPs owned by this slave, using UPDATE_QP */ - work->port = port; - work->slave = slave; - work->qos = vp_oper->state.default_qos; - work->vlan_id = vp_oper->state.default_vlan; - work->vlan_ix = vp_oper->vlan_idx; - work->priv = priv; - INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); - queue_work(priv->mfunc.master.comm_wq, &work->work); - - return 0; -} - - -static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) -{ - int port, err; - struct mlx4_vport_state *vp_admin; - struct mlx4_vport_oper_state *vp_oper; - - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - vp_oper->state = *vp_admin; - if (MLX4_VGT != vp_admin->default_vlan) { - err = __mlx4_register_vlan(&priv->dev, port, - vp_admin->default_vlan, &(vp_oper->vlan_idx)); - if (err) { - vp_oper->vlan_idx = NO_INDX; - mlx4_warn((&priv->dev), - "No vlan resorces slave %d, port %d\n", - slave, port); - return err; - } - mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n", - (int)(vp_oper->state.default_vlan), - vp_oper->vlan_idx, slave, port); - } - if (vp_admin->spoofchk) { - vp_oper->mac_idx = __mlx4_register_mac(&priv->dev, - port, - vp_admin->mac); - if (0 > vp_oper->mac_idx) { - err = vp_oper->mac_idx; - vp_oper->mac_idx = NO_INDX; - mlx4_warn((&priv->dev), - "No mac resources slave %d, port %d\n", - slave, port); - return err; - } - mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n", - (unsigned long long) vp_oper->state.mac, vp_oper->mac_idx, slave, port); - } - } - return 0; -} - -static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave) -{ - int port; - struct mlx4_vport_oper_state *vp_oper; - - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - if (NO_INDX != vp_oper->vlan_idx) { - __mlx4_unregister_vlan(&priv->dev, - port, vp_oper->state.default_vlan); - vp_oper->vlan_idx = NO_INDX; - } - if (NO_INDX != vp_oper->mac_idx) { - __mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac); - vp_oper->mac_idx = NO_INDX; - } - } - return; -} - -static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, - u16 param, u8 toggle) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - u32 reply; - u8 is_going_down = 0; - int i; - unsigned long flags; - - slave_state[slave].comm_toggle ^= 1; - reply = (u32) slave_state[slave].comm_toggle << 31; - if (toggle != slave_state[slave].comm_toggle) { - mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" - "STATE COMPROMISIED ***\n", toggle, slave); - goto reset_slave; - } - if (cmd == MLX4_COMM_CMD_RESET) { - mlx4_warn(dev, "Received reset from slave:%d\n", slave); - slave_state[slave].active = false; - slave_state[slave].old_vlan_api = false; - mlx4_master_deactivate_admin_state(priv, slave); - for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { - slave_state[slave].event_eq[i].eqn = -1; - slave_state[slave].event_eq[i].token = 0; - } - /*check if we are in the middle of FLR process, - if so return "retry" status to the slave*/ - if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) - goto inform_slave_state; - - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave); - - /* write the version in the event field */ - reply |= mlx4_comm_get_version(); - - goto reset_slave; - } - /*command from slave in the middle of FLR*/ - if (cmd != MLX4_COMM_CMD_RESET && - MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { - mlx4_warn(dev, "slave:%d is Trying to run cmd (0x%x) " - "in the middle of FLR\n", slave, cmd); - return; - } - - switch (cmd) { - case MLX4_COMM_CMD_VHCR0: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) - goto reset_slave; - slave_state[slave].vhcr_dma = ((u64) param) << 48; - priv->mfunc.master.slave_state[slave].cookie = 0; - break; - case MLX4_COMM_CMD_VHCR1: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) - goto reset_slave; - slave_state[slave].vhcr_dma |= ((u64) param) << 32; - break; - case MLX4_COMM_CMD_VHCR2: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) - goto reset_slave; - slave_state[slave].vhcr_dma |= ((u64) param) << 16; - break; - case MLX4_COMM_CMD_VHCR_EN: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) - goto reset_slave; - slave_state[slave].vhcr_dma |= param; - if (mlx4_master_activate_admin_state(priv, slave)) - goto reset_slave; - slave_state[slave].active = true; - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave); - break; - case MLX4_COMM_CMD_VHCR_POST: - if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && - (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) - goto reset_slave; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_master_process_vhcr(dev, slave, NULL)) { - mlx4_err(dev, "Failed processing vhcr for slave: %d," - " resetting slave.\n", slave); - mutex_unlock(&priv->cmd.slave_cmd_mutex); - goto reset_slave; - } - mutex_unlock(&priv->cmd.slave_cmd_mutex); - break; - default: - mlx4_warn(dev, "Bad comm cmd: %d from slave: %d\n", cmd, slave); - goto reset_slave; - } - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (!slave_state[slave].is_slave_going_down) - slave_state[slave].last_cmd = cmd; - else - is_going_down = 1; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - if (is_going_down) { - mlx4_warn(dev, "Slave is going down aborting command (%d)" - " executing from slave: %d\n", - cmd, slave); - return; - } - __raw_writel((__force u32) cpu_to_be32(reply), - &priv->mfunc.comm[slave].slave_read); - mmiowb(); - - return; - -reset_slave: - /* cleanup any slave resources */ - mlx4_delete_all_resources_for_slave(dev, slave); - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (!slave_state[slave].is_slave_going_down) - slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - /*with slave in the middle of flr, no need to clean resources again.*/ -inform_slave_state: - __raw_writel((__force u32) cpu_to_be32(reply), - &priv->mfunc.comm[slave].slave_read); - wmb(); -} - -/* master command processing */ -void mlx4_master_comm_channel(struct work_struct *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; - __be32 *bit_vec; - u32 comm_cmd; - u32 vec; - int i, j, slave; - int toggle; - int served = 0; - int reported = 0; - u32 slt; - - 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; - ++reported; - slave = (i * 32) + j; - comm_cmd = swab32(readl( - &mfunc->comm[slave].slave_write)); - slt = swab32(readl(&mfunc->comm[slave].slave_read)) - >> 31; - toggle = comm_cmd >> 31; - if (toggle != slt) { - if (master->slave_state[slave].comm_toggle - != slt) { - mlx4_info(dev, "slave %d out of sync." - " read toggle %d, state toggle %d. " - "Resynching.\n", slave, slt, - master->slave_state[slave].comm_toggle); - master->slave_state[slave].comm_toggle = - slt; - } - mlx4_master_do_cmd(dev, slave, - comm_cmd >> 16 & 0xff, - comm_cmd & 0xffff, toggle); - ++served; - } else - mlx4_err(dev, "slave %d out of sync." - " read toggle %d, write toggle %d.\n", slave, slt, - toggle); - } - } - - if (reported && reported != served) - mlx4_warn(dev, "Got command event with bitmask from %d slaves" - " but %d were served\n", - reported, served); -} -/* master command processing */ -void mlx4_master_arm_comm_channel(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, - struct mlx4_mfunc_master_ctx, - arm_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; - - if (mlx4_ARM_COMM_CHANNEL(dev)) - mlx4_warn(dev, "Failed to arm comm channel events\n"); -} - -static int sync_toggles(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int wr_toggle; - int rd_toggle; - unsigned long end; - - wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31; - end = jiffies + msecs_to_jiffies(5000); - - while (time_before(jiffies, end)) { - rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31; - if (rd_toggle == wr_toggle) { - priv->cmd.comm_toggle = rd_toggle; - return 0; - } - - cond_resched(); - } - - /* - * we could reach here if for example the previous VM using this - * function misbehaved and left the channel with unsynced state. We - * should fix this here and give this VM a chance to use a properly - * synced channel - */ - mlx4_warn(dev, "recovering from previously mis-behaved VM\n"); - __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read); - __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write); - priv->cmd.comm_toggle = 0; - - return 0; -} - -int mlx4_multi_func_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state; - int i, j, err, port; - - if (mlx4_is_master(dev)) - priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + - priv->fw.comm_base, MLX4_COMM_PAGESIZE); - else - priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, 2) + - MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); - if (!priv->mfunc.comm) { - mlx4_err(dev, "Couldn't map communication vector.\n"); - goto err_vhcr; - } - - if (mlx4_is_master(dev)) { - priv->mfunc.master.slave_state = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_slave_state), GFP_KERNEL); - if (!priv->mfunc.master.slave_state) - goto err_comm; - - priv->mfunc.master.vf_admin = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_admin_state), GFP_KERNEL); - if (!priv->mfunc.master.vf_admin) - goto err_comm_admin; - - priv->mfunc.master.vf_oper = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_oper_state), GFP_KERNEL); - if (!priv->mfunc.master.vf_oper) - goto err_comm_oper; - - for (i = 0; i < dev->num_slaves; ++i) { - s_state = &priv->mfunc.master.slave_state[i]; - s_state->last_cmd = MLX4_COMM_CMD_RESET; - mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); - for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) - s_state->event_eq[j].eqn = -1; - __raw_writel((__force u32) 0, - &priv->mfunc.comm[i].slave_write); - __raw_writel((__force u32) 0, - &priv->mfunc.comm[i].slave_read); - mmiowb(); - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - s_state->vlan_filter[port] = - kzalloc(sizeof(struct mlx4_vlan_fltr), - GFP_KERNEL); - if (!s_state->vlan_filter[port]) { - if (--port) - kfree(s_state->vlan_filter[port]); - goto err_slaves; - } - INIT_LIST_HEAD(&s_state->mcast_filters[port]); - priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX; - priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX; - } - spin_lock_init(&s_state->lock); - } - - memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size); - 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.arm_comm_work, - mlx4_master_arm_comm_channel); - INIT_WORK(&priv->mfunc.master.slave_event_work, - mlx4_gen_slave_eqe); - INIT_WORK(&priv->mfunc.master.slave_flr_event_work, - mlx4_master_handle_slave_flr); - spin_lock_init(&priv->mfunc.master.slave_state_lock); - spin_lock_init(&priv->mfunc.master.slave_eq.event_lock); - priv->mfunc.master.comm_wq = - create_singlethread_workqueue("mlx4_comm"); - if (!priv->mfunc.master.comm_wq) - goto err_slaves; - - if (mlx4_init_resource_tracker(dev)) - goto err_thread; - - err = mlx4_ARM_COMM_CHANNEL(dev); - if (err) { - mlx4_err(dev, " Failed to arm comm channel eq: %x\n", - err); - goto err_resource; - } - - } else { - err = sync_toggles(dev); - if (err) { - mlx4_err(dev, "Couldn't sync toggles\n"); - goto err_comm; - } - } - return 0; - -err_resource: - mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); -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++) - kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); - } - kfree(priv->mfunc.master.vf_oper); -err_comm_oper: - kfree(priv->mfunc.master.vf_admin); -err_comm_admin: - kfree(priv->mfunc.master.slave_state); -err_comm: - iounmap(priv->mfunc.comm); -err_vhcr: - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, - priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; - return -ENOMEM; -} - -int mlx4_cmd_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_init(&priv->cmd.hcr_mutex); - mutex_init(&priv->cmd.slave_cmd_mutex); - sema_init(&priv->cmd.poll_sem, 1); - priv->cmd.use_events = 0; - priv->cmd.toggle = 1; - - priv->cmd.hcr = NULL; - priv->mfunc.vhcr = NULL; - - if (!mlx4_is_slave(dev)) { - priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + - MLX4_HCR_BASE, MLX4_HCR_SIZE); - if (!priv->cmd.hcr) { - mlx4_err(dev, "Couldn't map command register.\n"); - return -ENOMEM; - } - } - - if (mlx4_is_mfunc(dev)) { - priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, - &priv->mfunc.vhcr_dma, - GFP_KERNEL); - if (!priv->mfunc.vhcr) { - mlx4_err(dev, "Couldn't allocate VHCR.\n"); - goto err_hcr; - } - } - - priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, - MLX4_MAILBOX_SIZE, - MLX4_MAILBOX_SIZE, 0); - if (!priv->cmd.pool) - goto err_vhcr; - - return 0; - -err_vhcr: - if (mlx4_is_mfunc(dev)) - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; - -err_hcr: - if (!mlx4_is_slave(dev)) - iounmap(priv->cmd.hcr); - return -ENOMEM; -} - -void mlx4_multi_func_cleanup(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, port; - - 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]); - } - kfree(priv->mfunc.master.slave_state); - kfree(priv->mfunc.master.vf_admin); - kfree(priv->mfunc.master.vf_oper); - } - - iounmap(priv->mfunc.comm); -} - -void mlx4_cmd_cleanup(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - pci_pool_destroy(priv->cmd.pool); - - if (!mlx4_is_slave(dev)) - iounmap(priv->cmd.hcr); - if (mlx4_is_mfunc(dev)) - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; -} - -/* - * Switch to using events to issue FW commands (can only be called - * after event queue for command events has been initialized). - */ -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), - GFP_KERNEL); - if (!priv->cmd.context) - return -ENOMEM; - - for (i = 0; i < priv->cmd.max_cmds; ++i) { - priv->cmd.context[i].token = i; - priv->cmd.context[i].next = i + 1; - } - - priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; - priv->cmd.free_head = 0; - - sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); - spin_lock_init(&priv->cmd.context_lock); - - for (priv->cmd.token_mask = 1; - priv->cmd.token_mask < priv->cmd.max_cmds; - priv->cmd.token_mask <<= 1) - ; /* nothing */ - --priv->cmd.token_mask; - - down(&priv->cmd.poll_sem); - priv->cmd.use_events = 1; - - return err; -} - -/* - * Switch back to polling (used when shutting down the device) - */ -void mlx4_cmd_use_polling(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - priv->cmd.use_events = 0; - - for (i = 0; i < priv->cmd.max_cmds; ++i) - down(&priv->cmd.event_sem); - - kfree(priv->cmd.context); - - up(&priv->cmd.poll_sem); -} - -struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) -{ - struct mlx4_cmd_mailbox *mailbox; - - mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); - if (!mailbox) - return ERR_PTR(-ENOMEM); - - mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, - &mailbox->dma); - if (!mailbox->buf) { - kfree(mailbox); - return ERR_PTR(-ENOMEM); - } - - memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); - - return mailbox; -} -EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); - -void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox) -{ - if (!mailbox) - return; - - pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); - kfree(mailbox); -} -EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); - -u32 mlx4_comm_get_version(void) -{ - return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; -} - -static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) -{ - if ((vf < 0) || (vf >= dev->num_vfs)) { - mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs); - return -EINVAL; - } - return (vf+1); -} - -int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if (!mlx4_is_master(dev)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - s_info->mac = mlx4_mac_to_u64(mac); - mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n", - vf, port, (unsigned long long) s_info->mac); - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); - -int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_oper_state *vf_oper; - struct mlx4_vport_state *vf_admin; - int slave; - - if ((!mlx4_is_master(dev)) || - !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) - return -EPROTONOSUPPORT; - - if ((vlan > 4095) || (qos > 7)) - return -EINVAL; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - - if ((0 == vlan) && (0 == qos)) - vf_admin->default_vlan = MLX4_VGT; - else - vf_admin->default_vlan = vlan; - vf_admin->default_qos = qos; - - if (priv->mfunc.master.slave_state[slave].active && - dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) { - mlx4_info(dev, "updating vf %d port %d config params immediately\n", - vf, port); - mlx4_master_immediate_activate_vlan_qos(priv, slave, port); - } - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); - - /* mlx4_get_slave_default_vlan - - * retrun true if VST ( default vlan) - * if VST will fill vlan & qos (if not NULL) */ -bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, u16 *vlan, u8 *qos) -{ - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_priv *priv; - - priv = mlx4_priv(dev); - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - - if (MLX4_VGT != vp_oper->state.default_vlan) { - if (vlan) - *vlan = vp_oper->state.default_vlan; - if (qos) - *qos = vp_oper->state.default_qos; - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); - -int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if ((!mlx4_is_master(dev)) || - !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - s_info->spoofchk = setting; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk); - -int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - struct mlx4_vport_oper_state *vp_oper; - int slave; - u8 link_stat_event; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - switch (link_state) { - case IFLA_VF_LINK_STATE_AUTO: - /* get link curent state */ - if (!priv->sense.do_sense_port[port]) - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; - else - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; - break; - - case IFLA_VF_LINK_STATE_ENABLE: - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; - break; - - case IFLA_VF_LINK_STATE_DISABLE: - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; - break; - - default: - mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", - link_state, slave, port); - return -EINVAL; - } - /* update the admin & oper state on the link state */ - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - s_info->link_state = link_state; - vp_oper->state.link_state = link_state; - - /* send event */ - mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event); - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); - -int mlx4_get_vf_link_state(struct mlx4_dev *dev, int port, int vf) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if (!mlx4_is_master(dev)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - - return s_info->link_state; -} -EXPORT_SYMBOL_GPL(mlx4_get_vf_link_state); - diff --git a/sys/ofed/drivers/net/mlx4/cq.c b/sys/ofed/drivers/net/mlx4/cq.c deleted file mode 100644 index b133ae615ea4..000000000000 --- a/sys/ofed/drivers/net/mlx4/cq.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/hardirq.h> -#include <linux/module.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/cq.h> - -#include "mlx4.h" -#include "icm.h" - -#define MLX4_CQ_STATUS_OK ( 0 << 28) -#define MLX4_CQ_STATUS_OVERFLOW ( 9 << 28) -#define MLX4_CQ_STATUS_WRITE_FAIL (10 << 28) -#define MLX4_CQ_FLAG_CC ( 1 << 18) -#define MLX4_CQ_FLAG_OI ( 1 << 17) -#define MLX4_CQ_STATE_ARMED ( 9 << 8) -#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8) -#define MLX4_EQ_STATE_FIRED (10 << 8) - -void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - struct mlx4_cq *cq; - - read_lock(&cq_table->cq_table_lock); - - cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree, - cqn & (dev->caps.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - - read_unlock(&cq_table->cq_table_lock); - - if (!cq) { - mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn); - return; - } - - ++cq->arm_sn; - - cq->comp(cq); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); -} - -void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - struct mlx4_cq *cq; - - read_lock(&cq_table->cq_table_lock); - - cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - - read_unlock(&cq_table->cq_table_lock); - - if (!cq) { - mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn); - return; - } - - cq->event(cq, event_type); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); -} - -static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num) -{ - return mlx4_cmd(dev, mailbox->dma, cq_num, 0, - MLX4_CMD_SW2HW_CQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num, u32 opmod) -{ - return mlx4_cmd(dev, mailbox->dma, cq_num, opmod, MLX4_CMD_MODIFY_CQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, - cq_num, mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, - u16 count, u16 period) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->cq_max_count = cpu_to_be16(count); - cq_context->cq_period = cpu_to_be16(period); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_modify); - -int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, - int entries, struct mlx4_mtt *mtt) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - u64 mtt_addr; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->logsize_usrpage = cpu_to_be32(ilog2(entries) << 24); - cq_context->log_page_size = mtt->page_shift - 12; - mtt_addr = mlx4_mtt_addr(dev, mtt); - cq_context->mtt_base_addr_h = mtt_addr >> 32; - cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 0); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_resize); - -int mlx4_cq_ignore_overrun(struct mlx4_dev *dev, struct mlx4_cq *cq) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->flags |= cpu_to_be32(MLX4_CQ_FLAG_OI); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 3); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_ignore_overrun); - -int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - int err; - - *cqn = mlx4_bitmap_alloc(&cq_table->bitmap); - if (*cqn == -1) - return -ENOMEM; - - err = mlx4_table_get(dev, &cq_table->table, *cqn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn); - if (err) - goto err_put; - return 0; - -err_put: - mlx4_table_put(dev, &cq_table->table, *cqn); - -err_out: - mlx4_bitmap_free(&cq_table->bitmap, *cqn, MLX4_NO_RR); - return err; -} - -static int mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, RES_CQ, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - else { - *cqn = get_param_l(&out_param); - return 0; - } - } - return __mlx4_cq_alloc_icm(dev, cqn); -} - -void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - - mlx4_table_put(dev, &cq_table->cmpt_table, cqn); - mlx4_table_put(dev, &cq_table->table, cqn); - mlx4_bitmap_free(&cq_table->bitmap, cqn, MLX4_NO_RR); -} - -static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, cqn); - err = mlx4_cmd(dev, in_param, RES_CQ, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed freeing cq:%d\n", cqn); - } else - __mlx4_cq_free_icm(dev, cqn); -} - -int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, - struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, - struct mlx4_cq *cq, unsigned vector, int collapsed, - int timestamp_en) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - u64 mtt_addr; - int err; - - if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) - return -EINVAL; - - cq->vector = vector; - - err = mlx4_cq_alloc_icm(dev, &cq->cqn); - if (err) - return err; - - spin_lock_irq(&cq_table->lock); - err = radix_tree_insert(&cq_table->tree, cq->cqn, cq); - spin_unlock_irq(&cq_table->lock); - if (err) - goto err_icm; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_radix; - } - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->flags = cpu_to_be32(!!collapsed << 18); - if (timestamp_en) - cq_context->flags |= cpu_to_be32(1 << 19); - - cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); - cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; - cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, mtt); - cq_context->mtt_base_addr_h = mtt_addr >> 32; - cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - cq_context->db_rec_addr = cpu_to_be64(db_rec); - - err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - goto err_radix; - - cq->cons_index = 0; - cq->arm_sn = 1; - cq->uar = uar; - atomic_set(&cq->refcount, 1); - init_completion(&cq->free); - - cq->eqn = priv->eq_table.eq[cq->vector].eqn; - cq->irq = priv->eq_table.eq[cq->vector].irq; - - return 0; - -err_radix: - spin_lock_irq(&cq_table->lock); - radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); - -err_icm: - mlx4_cq_free_icm(dev, cq->cqn); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_alloc); - -void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - int err; - - err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn); - if (err) - mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); - - synchronize_irq(priv->eq_table.eq[cq->vector].irq); - - spin_lock_irq(&cq_table->lock); - radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); - wait_for_completion(&cq->free); - - mlx4_cq_free_icm(dev, cq->cqn); -} -EXPORT_SYMBOL_GPL(mlx4_cq_free); - -int mlx4_init_cq_table(struct mlx4_dev *dev) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - int err; - - spin_lock_init(&cq_table->lock); - rwlock_init(&cq_table->cq_table_lock); - INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs, - dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0); - if (err) - return err; - - return 0; -} - -void mlx4_cleanup_cq_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - /* Nothing to do to clean up radix_tree */ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/en_cq.c b/sys/ofed/drivers/net/mlx4/en_cq.c deleted file mode 100644 index 591404d0a83c..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_cq.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <linux/mlx4/cq.h> -#include <linux/mlx4/qp.h> -#include <linux/mlx4/cmd.h> - -#include "mlx4_en.h" - - -static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) -{ - return; -} - - -int mlx4_en_create_cq(struct mlx4_en_priv *priv, - struct mlx4_en_cq **pcq, - int entries, int ring, enum cq_type mode, - int node) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq; - int err; - - cq = kzalloc_node(sizeof(struct mlx4_en_cq), GFP_KERNEL, node); - if (!cq) { - cq = kzalloc(sizeof(struct mlx4_en_cq), GFP_KERNEL); - if (!cq) { - en_err(priv, "Failed to allocate CW struture\n"); - return -ENOMEM; - } - } - - cq->size = entries; - cq->buf_size = cq->size * mdev->dev->caps.cqe_size; - - cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, - taskqueue_thread_enqueue, &cq->tq); - if (mode == RX) { - TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); - taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s rx cq", - if_name(priv->dev)); - - } else { - TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); - taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s tx cq", - if_name(priv->dev)); - } - - cq->ring = ring; - cq->is_tx = mode; - spin_lock_init(&cq->lock); - - err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, - cq->buf_size, 2 * PAGE_SIZE); - if (err) - goto err_cq; - - err = mlx4_en_map_buffer(&cq->wqres.buf); - if (err) - goto err_res; - - cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; - *pcq = cq; - - return 0; - -err_res: - mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); -err_cq: - kfree(cq); - return err; -} - - -int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, - int cq_idx) -{ - struct mlx4_en_dev *mdev = priv->mdev; - int err = 0; - char name[25]; - int timestamp_en = 0; - - cq->dev = mdev->pndev[priv->port]; - cq->mcq.set_ci_db = cq->wqres.db.db; - cq->mcq.arm_db = cq->wqres.db.db + 1; - *cq->mcq.set_ci_db = 0; - *cq->mcq.arm_db = 0; - memset(cq->buf, 0, cq->buf_size); - - if (cq->is_tx == RX) { - if (mdev->dev->caps.comp_pool) { - if (!cq->vector) { - sprintf(name, "%s-%d", if_name(priv->dev), - cq->ring); - /* Set IRQ for specific name (per ring) */ - if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { - cq->vector = (cq->ring + 1 + priv->port) - % mdev->dev->caps.num_comp_vectors; - mlx4_warn(mdev, "Failed Assigning an EQ to " - "%s ,Falling back to legacy EQ's\n", - name); - } - } - } else { - cq->vector = (cq->ring + 1 + priv->port) % - mdev->dev->caps.num_comp_vectors; - } - } else { - struct mlx4_en_cq *rx_cq; - /* - * For TX we use the same irq per - * ring we assigned for the RX - */ - cq_idx = cq_idx % priv->rx_ring_num; - rx_cq = priv->rx_cq[cq_idx]; - cq->vector = rx_cq->vector; - } - - if (!cq->is_tx) - cq->size = priv->rx_ring[cq->ring]->actual_size; - err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, - &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, - cq->vector, 0, timestamp_en); - if (err) - return err; - - cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; - cq->mcq.event = mlx4_en_cq_event; - - if (cq->is_tx) { - init_timer(&cq->timer); - cq->timer.function = mlx4_en_poll_tx_cq; - cq->timer.data = (unsigned long) cq; - } - - - return 0; -} - -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq = *pcq; - - taskqueue_drain(cq->tq, &cq->cq_task); - taskqueue_free(cq->tq); - mlx4_en_unmap_buffer(&cq->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); - if (priv->mdev->dev->caps.comp_pool && cq->vector) - mlx4_release_eq(priv->mdev->dev, cq->vector); - kfree(cq); - *pcq = NULL; -} - -void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - struct mlx4_en_dev *mdev = priv->mdev; - - taskqueue_drain(cq->tq, &cq->cq_task); - if (cq->is_tx) - del_timer_sync(&cq->timer); - - mlx4_cq_free(mdev->dev, &cq->mcq); -} - - -/* Set rx cq moderation parameters */ -int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, - cq->moder_cnt, cq->moder_time); -} - -int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, - &priv->mdev->uar_lock); - - return 0; -} - - diff --git a/sys/ofed/drivers/net/mlx4/en_main.c b/sys/ofed/drivers/net/mlx4/en_main.c deleted file mode 100644 index 7cff16bbba27..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_main.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/slab.h> - -#include <linux/mlx4/driver.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> - -#include "mlx4_en.h" - -/* Mellanox ConnectX HCA Ethernet driver */ - -#define MLX4_EN_PARM_INT(X, def_val, desc) \ - static unsigned int X = def_val;\ - module_param(X , uint, 0444); \ - MODULE_PARM_DESC(X, desc); - - -/* - * Device scope module parameters - */ - -/* Enable RSS UDP traffic */ -MLX4_EN_PARM_INT(udp_rss, 1, - "Enable RSS for incoming UDP traffic"); - -/* Priority pausing */ -MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." - " Per priority bit mask"); -MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." - " Per priority bit mask"); - -#define MAX_PFC_TX 0xff -#define MAX_PFC_RX 0xff - - -static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) -{ - struct mlx4_en_profile *params = &mdev->profile; - int i; - - params->udp_rss = udp_rss; - params->num_tx_rings_p_up = min_t(int, mp_ncpus, - MLX4_EN_MAX_TX_RING_P_UP); - if (params->udp_rss && !(mdev->dev->caps.flags - & MLX4_DEV_CAP_FLAG_UDP_RSS)) { - mlx4_warn(mdev, "UDP RSS is not supported on this device.\n"); - params->udp_rss = 0; - } - for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; - params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; - params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - params->prof[i].tx_ring_num = params->num_tx_rings_p_up * - MLX4_EN_NUM_UP; - params->prof[i].rss_rings = 0; - } - - return 0; -} - -static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port) -{ - struct mlx4_en_dev *endev = ctx; - - return endev->pndev[port]; -} - -static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, - enum mlx4_dev_event event, unsigned long port) -{ - struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr; - struct mlx4_en_priv *priv; - - switch (event) { - case MLX4_DEV_EVENT_PORT_UP: - case MLX4_DEV_EVENT_PORT_DOWN: - if (!mdev->pndev[port]) - return; - priv = netdev_priv(mdev->pndev[port]); - /* To prevent races, we poll the link state in a separate - task rather than changing it here */ - priv->link_state = event; - queue_work(mdev->workqueue, &priv->linkstate_task); - break; - - case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: - mlx4_err(mdev, "Internal error detected, restarting device\n"); - break; - - case MLX4_DEV_EVENT_SLAVE_INIT: - case MLX4_DEV_EVENT_SLAVE_SHUTDOWN: - break; - default: - if (port < 1 || port > dev->caps.num_ports || - !mdev->pndev[port]) - return; - mlx4_warn(mdev, "Unhandled event %d for port %d\n", event, - (int) port); - } -} - -static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) -{ - struct mlx4_en_dev *mdev = endev_ptr; - int i, ret; - - mutex_lock(&mdev->state_lock); - mdev->device_up = false; - mutex_unlock(&mdev->state_lock); - - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) - if (mdev->pndev[i]) - mlx4_en_destroy_netdev(mdev->pndev[i]); - - flush_workqueue(mdev->workqueue); - destroy_workqueue(mdev->workqueue); - ret = mlx4_mr_free(dev, &mdev->mr); - if (ret) - mlx4_err(mdev, "Error deregistering MR. The system may have become unstable."); - iounmap(mdev->uar_map); - mlx4_uar_free(dev, &mdev->priv_uar); - mlx4_pd_free(dev, mdev->priv_pdn); - kfree(mdev); -} - -static void *mlx4_en_add(struct mlx4_dev *dev) -{ - struct mlx4_en_dev *mdev; - int i; - int err; - - mdev = kzalloc(sizeof *mdev, GFP_KERNEL); - if (!mdev) { - dev_err(&dev->pdev->dev, "Device struct alloc failed, " - "aborting.\n"); - err = -ENOMEM; - goto err_free_res; - } - - if (mlx4_pd_alloc(dev, &mdev->priv_pdn)) - goto err_free_dev; - - if (mlx4_uar_alloc(dev, &mdev->priv_uar)) - goto err_pd; - - mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT, - PAGE_SIZE); - if (!mdev->uar_map) - goto err_uar; - spin_lock_init(&mdev->uar_lock); - - mdev->dev = dev; - mdev->dma_device = &(dev->pdev->dev); - mdev->pdev = dev->pdev; - mdev->device_up = false; - - mdev->LSO_support = !!(dev->caps.flags & (1 << 15)); - if (!mdev->LSO_support) - mlx4_warn(mdev, "LSO not supported, please upgrade to later " - "FW version to enable LSO\n"); - - if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull, - MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, - 0, 0, &mdev->mr)) { - mlx4_err(mdev, "Failed allocating memory region\n"); - goto err_map; - } - if (mlx4_mr_enable(mdev->dev, &mdev->mr)) { - mlx4_err(mdev, "Failed enabling memory region\n"); - goto err_mr; - } - - /* Build device profile according to supplied module parameters */ - err = mlx4_en_get_profile(mdev); - if (err) { - mlx4_err(mdev, "Bad module parameters, aborting.\n"); - goto err_mr; - } - - /* Configure which ports to start according to module parameters */ - mdev->port_cnt = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) - mdev->port_cnt++; - - - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (!dev->caps.comp_pool) { - mdev->profile.prof[i].rx_ring_num = - rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, - min_t(int, - dev->caps.num_comp_vectors, - DEF_RX_RINGS))); - } else { - mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( - min_t(int, dev->caps.comp_pool / - dev->caps.num_ports, MAX_MSIX_P_PORT)); - } - } - - /* Create our own workqueue for reset/multicast tasks - * Note: we cannot use the shared workqueue because of deadlocks caused - * by the rtnl lock */ - mdev->workqueue = create_singlethread_workqueue("mlx4_en"); - if (!mdev->workqueue) { - err = -ENOMEM; - goto err_mr; - } - - /* At this stage all non-port specific tasks are complete: - * mark the card state as up */ - mutex_init(&mdev->state_lock); - mdev->device_up = true; - - /* Setup ports */ - - /* Create a netdev for each port */ - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) - mdev->pndev[i] = NULL; - } - - return mdev; - -err_mr: - err = mlx4_mr_free(dev, &mdev->mr); - if (err) - mlx4_err(mdev, "Error deregistering MR. The system may have become unstable."); -err_map: - if (mdev->uar_map) - iounmap(mdev->uar_map); -err_uar: - mlx4_uar_free(dev, &mdev->priv_uar); -err_pd: - mlx4_pd_free(dev, mdev->priv_pdn); -err_free_dev: - kfree(mdev); -err_free_res: - return NULL; -} - -static struct mlx4_interface mlx4_en_interface = { - .add = mlx4_en_add, - .remove = mlx4_en_remove, - .event = mlx4_en_event, - .get_dev = mlx4_en_get_netdev, - .protocol = MLX4_PROT_ETH, -}; - -static void mlx4_en_verify_params(void) -{ - if (pfctx > MAX_PFC_TX) { - pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - " - "should be in range 0-0x%x, will be changed to default (0)\n", - pfctx, MAX_PFC_TX); - pfctx = 0; - } - - if (pfcrx > MAX_PFC_RX) { - pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - " - "should be in range 0-0x%x, will be changed to default (0)\n", - pfcrx, MAX_PFC_RX); - pfcrx = 0; - } -} - - -static int __init mlx4_en_init(void) -{ - mlx4_en_verify_params(); - -#ifdef CONFIG_DEBUG_FS - int err = 0; - err = mlx4_en_register_debugfs(); - if (err) - pr_err(KERN_ERR "Failed to register debugfs\n"); -#endif - return mlx4_register_interface(&mlx4_en_interface); -} - -static void __exit mlx4_en_cleanup(void) -{ - mlx4_unregister_interface(&mlx4_en_interface); -#ifdef CONFIG_DEBUG_FS - mlx4_en_unregister_debugfs(); -#endif -} - -module_init(mlx4_en_init); -module_exit(mlx4_en_cleanup); - -static int -mlxen_evhand(module_t mod, int event, void *arg) -{ - return (0); -} -static moduledata_t mlxen_mod = { - .name = "mlxen", - .evhand = mlxen_evhand, -}; -DECLARE_MODULE(mlxen, mlxen_mod, SI_SUB_OFED_PREINIT, SI_ORDER_ANY); -MODULE_DEPEND(mlxen, mlx4, 1, 1, 1); -MODULE_DEPEND(mlxen, linuxkpi, 1, 1, 1); diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c deleted file mode 100644 index 26a0c6ce7336..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_netdev.c +++ /dev/null @@ -1,2818 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <linux/etherdevice.h> -#include <linux/delay.h> -#include <linux/slab.h> -#ifdef CONFIG_NET_RX_BUSY_POLL -#include <net/busy_poll.h> -#endif - -#include <linux/list.h> -#include <linux/if_ether.h> - -#include <linux/mlx4/driver.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/cq.h> - -#include <sys/sockio.h> -#include <sys/sysctl.h> - -#include "mlx4_en.h" -#include "en_port.h" - -static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv); -static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv); -static int mlx4_en_unit; - -#ifdef CONFIG_NET_RX_BUSY_POLL -/* must be called with local_bh_disable()d */ -static int mlx4_en_low_latency_recv(struct napi_struct *napi) -{ - struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); - struct net_device *dev = cq->dev; - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; - int done; - - if (!priv->port_up) - return LL_FLUSH_FAILED; - - if (!mlx4_en_cq_lock_poll(cq)) - return LL_FLUSH_BUSY; - - done = mlx4_en_process_rx_cq(dev, cq, 4); -#ifdef LL_EXTENDED_STATS - if (done) - rx_ring->cleaned += done; - else - rx_ring->misses++; -#endif - - mlx4_en_cq_unlock_poll(cq); - - return done; -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -#ifdef CONFIG_RFS_ACCEL - -struct mlx4_en_filter { - struct list_head next; - struct work_struct work; - - u8 ip_proto; - __be32 src_ip; - __be32 dst_ip; - __be16 src_port; - __be16 dst_port; - - int rxq_index; - struct mlx4_en_priv *priv; - u32 flow_id; /* RFS infrastructure id */ - int id; /* mlx4_en driver id */ - u64 reg_id; /* Flow steering API id */ - u8 activated; /* Used to prevent expiry before filter - * is attached - */ - struct hlist_node filter_chain; -}; - -static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); - -static enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) -{ - switch (ip_proto) { - case IPPROTO_UDP: - return MLX4_NET_TRANS_RULE_ID_UDP; - case IPPROTO_TCP: - return MLX4_NET_TRANS_RULE_ID_TCP; - default: - return -EPROTONOSUPPORT; - } -}; - -static void mlx4_en_filter_work(struct work_struct *work) -{ - struct mlx4_en_filter *filter = container_of(work, - struct mlx4_en_filter, - work); - struct mlx4_en_priv *priv = filter->priv; - struct mlx4_spec_list spec_tcp_udp = { - .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), - { - .tcp_udp = { - .dst_port = filter->dst_port, - .dst_port_msk = (__force __be16)-1, - .src_port = filter->src_port, - .src_port_msk = (__force __be16)-1, - }, - }, - }; - struct mlx4_spec_list spec_ip = { - .id = MLX4_NET_TRANS_RULE_ID_IPV4, - { - .ipv4 = { - .dst_ip = filter->dst_ip, - .dst_ip_msk = (__force __be32)-1, - .src_ip = filter->src_ip, - .src_ip_msk = (__force __be32)-1, - }, - }, - }; - struct mlx4_spec_list spec_eth = { - .id = MLX4_NET_TRANS_RULE_ID_ETH, - }; - struct mlx4_net_trans_rule rule = { - .list = LIST_HEAD_INIT(rule.list), - .queue_mode = MLX4_NET_TRANS_Q_LIFO, - .exclusive = 1, - .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, - .port = priv->port, - .priority = MLX4_DOMAIN_RFS, - }; - int rc; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - if (spec_tcp_udp.id < 0) { - en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", - filter->ip_proto); - goto ignore; - } - list_add_tail(&spec_eth.list, &rule.list); - list_add_tail(&spec_ip.list, &rule.list); - list_add_tail(&spec_tcp_udp.list, &rule.list); - - rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; - memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); - memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - - filter->activated = 0; - - if (filter->reg_id) { - rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); - if (rc && rc != -ENOENT) - en_err(priv, "Error detaching flow. rc = %d\n", rc); - } - - rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); - if (rc) - en_err(priv, "Error attaching flow. err = %d\n", rc); - -ignore: - mlx4_en_filter_rfs_expire(priv); - - filter->activated = 1; -} - -static inline struct hlist_head * -filter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, - __be16 src_port, __be16 dst_port) -{ - unsigned long l; - int bucket_idx; - - l = (__force unsigned long)src_port | - ((__force unsigned long)dst_port << 2); - l ^= (__force unsigned long)(src_ip ^ dst_ip); - - bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); - - return &priv->filter_hash[bucket_idx]; -} - -static struct mlx4_en_filter * -mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, - __be32 dst_ip, u8 ip_proto, __be16 src_port, - __be16 dst_port, u32 flow_id) -{ - struct mlx4_en_filter *filter = NULL; - - filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); - if (!filter) - return NULL; - - filter->priv = priv; - filter->rxq_index = rxq_index; - INIT_WORK(&filter->work, mlx4_en_filter_work); - - filter->src_ip = src_ip; - filter->dst_ip = dst_ip; - filter->ip_proto = ip_proto; - filter->src_port = src_port; - filter->dst_port = dst_port; - - filter->flow_id = flow_id; - - filter->id = priv->last_filter_id++ % RPS_NO_FILTER; - - list_add_tail(&filter->next, &priv->filters); - hlist_add_head(&filter->filter_chain, - filter_hash_bucket(priv, src_ip, dst_ip, src_port, - dst_port)); - - return filter; -} - -static void mlx4_en_filter_free(struct mlx4_en_filter *filter) -{ - struct mlx4_en_priv *priv = filter->priv; - int rc; - - list_del(&filter->next); - - rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); - if (rc && rc != -ENOENT) - en_err(priv, "Error detaching flow. rc = %d\n", rc); - - kfree(filter); -} - -static inline struct mlx4_en_filter * -mlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, - u8 ip_proto, __be16 src_port, __be16 dst_port) -{ - struct mlx4_en_filter *filter; - struct mlx4_en_filter *ret = NULL; - - hlist_for_each_entry(filter, - filter_hash_bucket(priv, src_ip, dst_ip, - src_port, dst_port), - filter_chain) { - if (filter->src_ip == src_ip && - filter->dst_ip == dst_ip && - filter->ip_proto == ip_proto && - filter->src_port == src_port && - filter->dst_port == dst_port) { - ret = filter; - break; - } - } - - return ret; -} - -static int -mlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, - u16 rxq_index, u32 flow_id) -{ - struct mlx4_en_priv *priv = netdev_priv(net_dev); - struct mlx4_en_filter *filter; - const struct iphdr *ip; - const __be16 *ports; - u8 ip_proto; - __be32 src_ip; - __be32 dst_ip; - __be16 src_port; - __be16 dst_port; - int nhoff = skb_network_offset(skb); - int ret = 0; - - if (skb->protocol != htons(ETH_P_IP)) - return -EPROTONOSUPPORT; - - ip = (const struct iphdr *)(skb->data + nhoff); - if (ip_is_fragment(ip)) - return -EPROTONOSUPPORT; - - if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) - return -EPROTONOSUPPORT; - ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); - - ip_proto = ip->protocol; - src_ip = ip->saddr; - dst_ip = ip->daddr; - src_port = ports[0]; - dst_port = ports[1]; - - spin_lock_bh(&priv->filters_lock); - filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, - src_port, dst_port); - if (filter) { - if (filter->rxq_index == rxq_index) - goto out; - - filter->rxq_index = rxq_index; - } else { - filter = mlx4_en_filter_alloc(priv, rxq_index, - src_ip, dst_ip, ip_proto, - src_port, dst_port, flow_id); - if (!filter) { - ret = -ENOMEM; - goto err; - } - } - - queue_work(priv->mdev->workqueue, &filter->work); - -out: - ret = filter->id; -err: - spin_unlock_bh(&priv->filters_lock); - - return ret; -} - -void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *rx_ring) -{ - struct mlx4_en_filter *filter, *tmp; - LIST_HEAD(del_list); - - spin_lock_bh(&priv->filters_lock); - list_for_each_entry_safe(filter, tmp, &priv->filters, next) { - list_move(&filter->next, &del_list); - hlist_del(&filter->filter_chain); - } - spin_unlock_bh(&priv->filters_lock); - - list_for_each_entry_safe(filter, tmp, &del_list, next) { - cancel_work_sync(&filter->work); - mlx4_en_filter_free(filter); - } -} - -static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) -{ - struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; - LIST_HEAD(del_list); - int i = 0; - - spin_lock_bh(&priv->filters_lock); - list_for_each_entry_safe(filter, tmp, &priv->filters, next) { - if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) - break; - - if (filter->activated && - !work_pending(&filter->work) && - rps_may_expire_flow(priv->dev, - filter->rxq_index, filter->flow_id, - filter->id)) { - list_move(&filter->next, &del_list); - hlist_del(&filter->filter_chain); - } else - last_filter = filter; - - i++; - } - - if (last_filter && (&last_filter->next != priv->filters.next)) - list_move(&priv->filters, &last_filter->next); - - spin_unlock_bh(&priv->filters_lock); - - list_for_each_entry_safe(filter, tmp, &del_list, next) - mlx4_en_filter_free(filter); -} -#endif - -static void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - int idx; - - if (arg != priv) - return; - - en_dbg(HW, priv, "adding VLAN:%d\n", vid); - - set_bit(vid, priv->active_vlans); - - /* Add VID to port VLAN filter */ - mutex_lock(&mdev->state_lock); - if (mdev->device_up && priv->port_up) { - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed configuring VLAN filter\n"); - } - if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx)) - en_dbg(HW, priv, "failed adding vlan %d\n", vid); - mutex_unlock(&mdev->state_lock); - -} - -static void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - if (arg != priv) - return; - - en_dbg(HW, priv, "Killing VID:%d\n", vid); - - clear_bit(vid, priv->active_vlans); - - /* Remove VID from port VLAN filter */ - mutex_lock(&mdev->state_lock); - mlx4_unregister_vlan(mdev->dev, priv->port, vid); - - if (mdev->device_up && priv->port_up) { - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed configuring VLAN filter\n"); - } - mutex_unlock(&mdev->state_lock); - -} - -static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, - unsigned char *mac, int *qpn, u64 *reg_id) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - int err; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_B0: { - struct mlx4_qp qp; - u8 gid[16] = {0}; - - qp.qpn = *qpn; - memcpy(&gid[10], mac, ETH_ALEN); - gid[5] = priv->port; - - err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); - break; - } - case MLX4_STEERING_MODE_DEVICE_MANAGED: { - struct mlx4_spec_list spec_eth = { {NULL} }; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - struct mlx4_net_trans_rule rule = { - .queue_mode = MLX4_NET_TRANS_Q_FIFO, - .exclusive = 0, - .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, - .priority = MLX4_DOMAIN_NIC, - }; - - rule.port = priv->port; - rule.qpn = *qpn; - INIT_LIST_HEAD(&rule.list); - - spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; - memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); - memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - list_add_tail(&spec_eth.list, &rule.list); - - err = mlx4_flow_attach(dev, &rule, reg_id); - break; - } - default: - return -EINVAL; - } - if (err) - en_warn(priv, "Failed Attaching Unicast\n"); - - return err; -} - -static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, - unsigned char *mac, int qpn, u64 reg_id) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_B0: { - struct mlx4_qp qp; - u8 gid[16] = {0}; - - qp.qpn = qpn; - memcpy(&gid[10], mac, ETH_ALEN); - gid[5] = priv->port; - - mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); - break; - } - case MLX4_STEERING_MODE_DEVICE_MANAGED: { - mlx4_flow_detach(dev, reg_id); - break; - } - default: - en_err(priv, "Invalid steering mode.\n"); - } -} - -static int mlx4_en_get_qp(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - struct mlx4_mac_entry *entry; - int index = 0; - int err = 0; - u64 reg_id; - int *qpn = &priv->base_qpn; - u64 mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); - - en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", - IF_LLADDR(priv->dev)); - index = mlx4_register_mac(dev, priv->port, mac); - if (index < 0) { - err = index; - en_err(priv, "Failed adding MAC: %pM\n", - IF_LLADDR(priv->dev)); - return err; - } - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { - int base_qpn = mlx4_get_base_qpn(dev, priv->port); - *qpn = base_qpn + index; - return 0; - } - - err = mlx4_qp_reserve_range(dev, 1, 1, qpn, 0); - en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); - if (err) { - en_err(priv, "Failed to reserve qp for mac registration\n"); - goto qp_err; - } - - err = mlx4_en_uc_steer_add(priv, IF_LLADDR(priv->dev), qpn, ®_id); - if (err) - goto steer_err; - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - err = -ENOMEM; - goto alloc_err; - } - memcpy(entry->mac, IF_LLADDR(priv->dev), sizeof(entry->mac)); - entry->reg_id = reg_id; - - hlist_add_head(&entry->hlist, - &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); - - return 0; - -alloc_err: - mlx4_en_uc_steer_release(priv, IF_LLADDR(priv->dev), *qpn, reg_id); - -steer_err: - mlx4_qp_release_range(dev, *qpn, 1); - -qp_err: - mlx4_unregister_mac(dev, priv->port, mac); - return err; -} - -static void mlx4_en_put_qp(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - int qpn = priv->base_qpn; - u64 mac; - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { - mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); - en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", - IF_LLADDR(priv->dev)); - mlx4_unregister_mac(dev, priv->port, mac); - } else { - struct mlx4_mac_entry *entry; - struct hlist_node *tmp; - struct hlist_head *bucket; - unsigned int i; - - for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { - bucket = &priv->mac_hash[i]; - hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { - mac = mlx4_mac_to_u64(entry->mac); - en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", - entry->mac); - mlx4_en_uc_steer_release(priv, entry->mac, - qpn, entry->reg_id); - - mlx4_unregister_mac(dev, priv->port, mac); - hlist_del(&entry->hlist); - kfree(entry); - } - } - - en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", - priv->port, qpn); - mlx4_qp_release_range(dev, qpn, 1); - priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; - } -} - -static void mlx4_en_clear_list(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_mc_list *tmp, *mc_to_del; - - list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { - list_del(&mc_to_del->list); - kfree(mc_to_del); - } -} - -static void mlx4_en_cache_mclist(struct net_device *dev) -{ - struct ifmultiaddr *ifma; - struct mlx4_en_mc_list *tmp; - struct mlx4_en_priv *priv = netdev_priv(dev); - - if_maddr_rlock(dev); - TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != - ETHER_ADDR_LEN) - continue; - /* Make sure the list didn't grow. */ - tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); - if (tmp == NULL) { - en_err(priv, "Failed to allocate multicast list\n"); - break; - } - memcpy(tmp->addr, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN); - list_add_tail(&tmp->list, &priv->mc_list); - } - if_maddr_runlock(dev); -} - -static void update_mclist_flags(struct mlx4_en_priv *priv, - struct list_head *dst, - struct list_head *src) -{ - struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; - bool found; - - /* Find all the entries that should be removed from dst, - * These are the entries that are not found in src - */ - list_for_each_entry(dst_tmp, dst, list) { - found = false; - list_for_each_entry(src_tmp, src, list) { - if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { - found = true; - break; - } - } - if (!found) - dst_tmp->action = MCLIST_REM; - } - - /* Add entries that exist in src but not in dst - * mark them as need to add - */ - list_for_each_entry(src_tmp, src, list) { - found = false; - list_for_each_entry(dst_tmp, dst, list) { - if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { - dst_tmp->action = MCLIST_NONE; - found = true; - break; - } - } - if (!found) { - new_mc = kmalloc(sizeof(struct mlx4_en_mc_list), - GFP_KERNEL); - if (!new_mc) { - en_err(priv, "Failed to allocate current multicast list\n"); - return; - } - memcpy(new_mc, src_tmp, - sizeof(struct mlx4_en_mc_list)); - new_mc->action = MCLIST_ADD; - list_add_tail(&new_mc->list, dst); - } - } -} - -static void mlx4_en_set_rx_mode(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (!priv->port_up) - return; - - queue_work(priv->mdev->workqueue, &priv->rx_mode_task); -} - -static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, - struct mlx4_en_dev *mdev) -{ - int err = 0; - if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { - priv->flags |= MLX4_EN_FLAG_PROMISC; - - /* Enable promiscouos mode */ - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_add(mdev->dev, - priv->port, - priv->base_qpn, - MLX4_FS_ALL_DEFAULT); - if (err) - en_err(priv, "Failed enabling promiscuous mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_unicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed enabling unicast promiscuous mode\n"); - - /* Add the default qp number as multicast - * promisc - */ - if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { - err = mlx4_multicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed enabling multicast promiscuous mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - } - break; - - case MLX4_STEERING_MODE_A0: - err = mlx4_SET_PORT_qpn_calc(mdev->dev, - priv->port, - priv->base_qpn, - 1); - if (err) - en_err(priv, "Failed enabling promiscuous mode\n"); - break; - } - - /* Disable port multicast filter (unconditionally) */ - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - } -} - -static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, - struct mlx4_en_dev *mdev) -{ - int err = 0; - - priv->flags &= ~MLX4_EN_FLAG_PROMISC; - - /* Disable promiscouos mode */ - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_ALL_DEFAULT); - if (err) - en_err(priv, "Failed disabling promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_unicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed disabling unicast promiscuous mode\n"); - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - err = mlx4_multicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed disabling multicast promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - break; - - case MLX4_STEERING_MODE_A0: - err = mlx4_SET_PORT_qpn_calc(mdev->dev, - priv->port, - priv->base_qpn, 0); - if (err) - en_err(priv, "Failed disabling promiscuous mode\n"); - break; - } -} - -static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, - struct net_device *dev, - struct mlx4_en_dev *mdev) -{ - struct mlx4_en_mc_list *mclist, *tmp; - u8 mc_list[16] = {0}; - int err = 0; - u64 mcast_addr = 0; - - - /* Enable/disable the multicast filter according to IFF_ALLMULTI */ - if (dev->if_flags & IFF_ALLMULTI) { - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - - /* Add the default qp number as multicast promisc */ - if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_add(mdev->dev, - priv->port, - priv->base_qpn, - MLX4_FS_MC_DEFAULT); - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_multicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - break; - - case MLX4_STEERING_MODE_A0: - break; - } - if (err) - en_err(priv, "Failed entering multicast promisc mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - } - } else { - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_MC_DEFAULT); - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_multicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - break; - - case MLX4_STEERING_MODE_A0: - break; - } - if (err) - en_err(priv, "Failed disabling multicast promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - - /* Flush mcast filter and init it with broadcast address */ - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, - 1, MLX4_MCAST_CONFIG); - - /* Update multicast list - we cache all addresses so they won't - * change while HW is updated holding the command semaphor */ - mlx4_en_cache_mclist(dev); - list_for_each_entry(mclist, &priv->mc_list, list) { - mcast_addr = mlx4_mac_to_u64(mclist->addr); - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, - mcast_addr, 0, MLX4_MCAST_CONFIG); - } - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_ENABLE); - if (err) - en_err(priv, "Failed enabling multicast filter\n"); - - update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); - list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { - if (mclist->action == MCLIST_REM) { - /* detach this address and delete from list */ - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - mc_list[5] = priv->port; - err = mlx4_multicast_detach(mdev->dev, - &priv->rss_map.indir_qp, - mc_list, - MLX4_PROT_ETH, - mclist->reg_id); - if (err) - en_err(priv, "Fail to detach multicast address\n"); - - /* remove from list */ - list_del(&mclist->list); - kfree(mclist); - } else if (mclist->action == MCLIST_ADD) { - /* attach the address */ - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - /* needed for B0 steering support */ - mc_list[5] = priv->port; - err = mlx4_multicast_attach(mdev->dev, - &priv->rss_map.indir_qp, - mc_list, - priv->port, 0, - MLX4_PROT_ETH, - &mclist->reg_id); - if (err) - en_err(priv, "Fail to attach multicast address\n"); - - } - } - } -} - -static void mlx4_en_do_set_rx_mode(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - rx_mode_task); - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - - - mutex_lock(&mdev->state_lock); - if (!mdev->device_up) { - en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); - goto out; - } - if (!priv->port_up) { - en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); - goto out; - } - if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { - if (priv->port_state.link_state) { - priv->last_link_state = MLX4_DEV_EVENT_PORT_UP; - /* update netif baudrate */ - priv->dev->if_baudrate = - IF_Mbps(priv->port_state.link_speed); - /* Important note: the following call for if_link_state_change - * is needed for interface up scenario (start port, link state - * change) */ - if_link_state_change(priv->dev, LINK_STATE_UP); - en_dbg(HW, priv, "Link Up\n"); - } - } - - /* Promsicuous mode: disable all filters */ - if ((dev->if_flags & IFF_PROMISC) || - (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { - mlx4_en_set_promisc_mode(priv, mdev); - goto out; - } - - /* Not in promiscuous mode */ - if (priv->flags & MLX4_EN_FLAG_PROMISC) - mlx4_en_clear_promisc_mode(priv, mdev); - - mlx4_en_do_multicast(priv, dev, mdev); -out: - mutex_unlock(&mdev->state_lock); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void mlx4_en_netpoll(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_cq *cq; - unsigned long flags; - int i; - - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - spin_lock_irqsave(&cq->lock, flags); - napi_synchronize(&cq->napi); - mlx4_en_process_rx_cq(dev, cq, 0); - spin_unlock_irqrestore(&cq->lock, flags); - } -} -#endif - -static void mlx4_en_watchdog_timeout(void *arg) -{ - struct mlx4_en_priv *priv = arg; - struct mlx4_en_dev *mdev = priv->mdev; - - en_dbg(DRV, priv, "Scheduling watchdog\n"); - queue_work(mdev->workqueue, &priv->watchdog_task); - if (priv->port_up) - callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, - mlx4_en_watchdog_timeout, priv); -} - - - -static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) -{ - struct mlx4_en_cq *cq; - int i; - - /* If we haven't received a specific coalescing setting - * (module param), we set the moderation parameters as follows: - * - moder_cnt is set to the number of mtu sized packets to - * satisfy our coelsing target. - * - moder_time is set to a fixed value. - */ - priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1; - priv->rx_usecs = MLX4_EN_RX_COAL_TIME; - priv->tx_frames = MLX4_EN_TX_COAL_PKTS; - priv->tx_usecs = MLX4_EN_TX_COAL_TIME; - en_dbg(INTR, priv, "Default coalesing params for mtu: %u - " - "rx_frames:%d rx_usecs:%d\n", - (unsigned)priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs); - - /* Setup cq moderation params */ - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - cq->moder_cnt = priv->rx_frames; - cq->moder_time = priv->rx_usecs; - priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; - priv->last_moder_packets[i] = 0; - priv->last_moder_bytes[i] = 0; - } - - for (i = 0; i < priv->tx_ring_num; i++) { - cq = priv->tx_cq[i]; - cq->moder_cnt = priv->tx_frames; - cq->moder_time = priv->tx_usecs; - } - - /* Reset auto-moderation params */ - priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; - priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; - priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; - priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; - priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; - priv->adaptive_rx_coal = 1; - priv->last_moder_jiffies = 0; - priv->last_moder_tx_packets = 0; -} - -static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) -{ - unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); - struct mlx4_en_cq *cq; - unsigned long packets; - unsigned long rate; - unsigned long avg_pkt_size; - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_pkt_diff; - int moder_time; - int ring, err; - - if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) - return; - - for (ring = 0; ring < priv->rx_ring_num; ring++) { - spin_lock(&priv->stats_lock); - rx_packets = priv->rx_ring[ring]->packets; - rx_bytes = priv->rx_ring[ring]->bytes; - spin_unlock(&priv->stats_lock); - - rx_pkt_diff = ((unsigned long) (rx_packets - - priv->last_moder_packets[ring])); - packets = rx_pkt_diff; - rate = packets * HZ / period; - avg_pkt_size = packets ? ((unsigned long) (rx_bytes - - priv->last_moder_bytes[ring])) / packets : 0; - - /* Apply auto-moderation only when packet rate - * exceeds a rate that it matters */ - if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && - avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { - if (rate < priv->pkt_rate_low) - moder_time = priv->rx_usecs_low; - else if (rate > priv->pkt_rate_high) - moder_time = priv->rx_usecs_high; - else - moder_time = (rate - priv->pkt_rate_low) * - (priv->rx_usecs_high - priv->rx_usecs_low) / - (priv->pkt_rate_high - priv->pkt_rate_low) + - priv->rx_usecs_low; - } else { - moder_time = priv->rx_usecs_low; - } - - if (moder_time != priv->last_moder_time[ring]) { - priv->last_moder_time[ring] = moder_time; - cq = priv->rx_cq[ring]; - cq->moder_time = moder_time; - err = mlx4_en_set_cq_moder(priv, cq); - if (err) - en_err(priv, "Failed modifying moderation for cq:%d\n", - ring); - } - priv->last_moder_packets[ring] = rx_packets; - priv->last_moder_bytes[ring] = rx_bytes; - } - - priv->last_moder_jiffies = jiffies; -} - -static void mlx4_en_do_get_stats(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, - stats_task); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - mutex_lock(&mdev->state_lock); - if (mdev->device_up) { - if (priv->port_up) { - err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); - if (err) - en_dbg(HW, priv, "Could not update stats\n"); - - mlx4_en_auto_moderation(priv); - } - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); - } - mutex_unlock(&mdev->state_lock); -} - -/* mlx4_en_service_task - Run service task for tasks that needed to be done - * periodically - */ -static void mlx4_en_service_task(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, - service_task); - struct mlx4_en_dev *mdev = priv->mdev; - - mutex_lock(&mdev->state_lock); - if (mdev->device_up) { - queue_delayed_work(mdev->workqueue, &priv->service_task, - SERVICE_TASK_DELAY); - } - mutex_unlock(&mdev->state_lock); -} - -static void mlx4_en_linkstate(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - linkstate_task); - struct mlx4_en_dev *mdev = priv->mdev; - int linkstate = priv->link_state; - - mutex_lock(&mdev->state_lock); - /* If observable port state changed set carrier state and - * report to system log */ - if (priv->last_link_state != linkstate) { - if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { - en_info(priv, "Link Down\n"); - if_link_state_change(priv->dev, LINK_STATE_DOWN); - /* update netif baudrate */ - priv->dev->if_baudrate = 0; - - /* make sure the port is up before notifying the OS. - * This is tricky since we get here on INIT_PORT and - * in such case we can't tell the OS the port is up. - * To solve this there is a call to if_link_state_change - * in set_rx_mode. - * */ - } else if (priv->port_up && (linkstate == MLX4_DEV_EVENT_PORT_UP)){ - if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) - en_info(priv, "Query port failed\n"); - priv->dev->if_baudrate = - IF_Mbps(priv->port_state.link_speed); - en_info(priv, "Link Up\n"); - if_link_state_change(priv->dev, LINK_STATE_UP); - } - } - priv->last_link_state = linkstate; - mutex_unlock(&mdev->state_lock); -} - - -int mlx4_en_start_port(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq; - struct mlx4_en_tx_ring *tx_ring; - int rx_index = 0; - int tx_index = 0; - int err = 0; - int i; - int j; - u8 mc_list[16] = {0}; - - - if (priv->port_up) { - en_dbg(DRV, priv, "start port called while port already up\n"); - return 0; - } - - INIT_LIST_HEAD(&priv->mc_list); - INIT_LIST_HEAD(&priv->curr_list); - INIT_LIST_HEAD(&priv->ethtool_list); - - /* Calculate Rx buf size */ - dev->if_mtu = min(dev->if_mtu, priv->max_mtu); - mlx4_en_calc_rx_buf(dev); - en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size); - - /* Configure rx cq's and rings */ - err = mlx4_en_activate_rx_rings(priv); - if (err) { - en_err(priv, "Failed to activate RX rings\n"); - return err; - } - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - - mlx4_en_cq_init_lock(cq); - err = mlx4_en_activate_cq(priv, cq, i); - if (err) { - en_err(priv, "Failed activating Rx CQ\n"); - goto cq_err; - } - for (j = 0; j < cq->size; j++) - cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; - err = mlx4_en_set_cq_moder(priv, cq); - if (err) { - en_err(priv, "Failed setting cq moderation parameters"); - mlx4_en_deactivate_cq(priv, cq); - goto cq_err; - } - mlx4_en_arm_cq(priv, cq); - priv->rx_ring[i]->cqn = cq->mcq.cqn; - ++rx_index; - } - - /* Set qp number */ - en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); - err = mlx4_en_get_qp(priv); - if (err) { - en_err(priv, "Failed getting eth qp\n"); - goto cq_err; - } - mdev->mac_removed[priv->port] = 0; - - /* gets default allocated counter index from func cap */ - /* or sink counter index if no resources */ - priv->counter_index = mdev->dev->caps.def_counter_index[priv->port - 1]; - - en_dbg(DRV, priv, "%s: default counter index %d for port %d\n", - __func__, priv->counter_index, priv->port); - - err = mlx4_en_config_rss_steer(priv); - if (err) { - en_err(priv, "Failed configuring rss steering\n"); - goto mac_err; - } - - err = mlx4_en_create_drop_qp(priv); - if (err) - goto rss_err; - - /* Configure tx cq's and rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - /* Configure cq */ - cq = priv->tx_cq[i]; - err = mlx4_en_activate_cq(priv, cq, i); - if (err) { - en_err(priv, "Failed activating Tx CQ\n"); - goto tx_err; - } - err = mlx4_en_set_cq_moder(priv, cq); - if (err) { - en_err(priv, "Failed setting cq moderation parameters"); - mlx4_en_deactivate_cq(priv, cq); - goto tx_err; - } - en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); - cq->buf->wqe_index = cpu_to_be16(0xffff); - - /* Configure ring */ - tx_ring = priv->tx_ring[i]; - - err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, - i / priv->num_tx_rings_p_up); - if (err) { - en_err(priv, "Failed activating Tx ring %d\n", i); - mlx4_en_deactivate_cq(priv, cq); - goto tx_err; - } - - /* Arm CQ for TX completions */ - mlx4_en_arm_cq(priv, cq); - - /* Set initial ownership of all Tx TXBBs to SW (1) */ - for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) - *((u32 *) (tx_ring->buf + j)) = 0xffffffff; - ++tx_index; - } - - /* Configure port */ - err = mlx4_SET_PORT_general(mdev->dev, priv->port, - priv->rx_mb_size, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - if (err) { - en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", - priv->port, err); - goto tx_err; - } - /* Set default qp number */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); - if (err) { - en_err(priv, "Failed setting default qp numbers\n"); - goto tx_err; - } - - /* Init port */ - en_dbg(HW, priv, "Initializing port\n"); - err = mlx4_INIT_PORT(mdev->dev, priv->port); - if (err) { - en_err(priv, "Failed Initializing port\n"); - goto tx_err; - } - - /* Attach rx QP to bradcast address */ - memset(&mc_list[10], 0xff, ETH_ALEN); - mc_list[5] = priv->port; /* needed for B0 steering support */ - if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, - priv->port, 0, MLX4_PROT_ETH, - &priv->broadcast_id)) - mlx4_warn(mdev, "Failed Attaching Broadcast\n"); - - /* Must redo promiscuous mode setup. */ - priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); - - /* Schedule multicast task to populate multicast list */ - queue_work(mdev->workqueue, &priv->rx_mode_task); - - mlx4_set_stats_bitmap(mdev->dev, priv->stats_bitmap); - - priv->port_up = true; - - /* Enable the queues. */ - dev->if_drv_flags &= ~IFF_DRV_OACTIVE; - dev->if_drv_flags |= IFF_DRV_RUNNING; -#ifdef CONFIG_DEBUG_FS - mlx4_en_create_debug_files(priv); -#endif - callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, - mlx4_en_watchdog_timeout, priv); - - - return 0; - -tx_err: - while (tx_index--) { - mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[tx_index]); - mlx4_en_deactivate_cq(priv, priv->tx_cq[tx_index]); - } - mlx4_en_destroy_drop_qp(priv); -rss_err: - mlx4_en_release_rss_steer(priv); -mac_err: - mlx4_en_put_qp(priv); -cq_err: - while (rx_index--) - mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); - for (i = 0; i < priv->rx_ring_num; i++) - mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); - - return err; /* need to close devices */ -} - - -void mlx4_en_stop_port(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_mc_list *mclist, *tmp; - int i; - u8 mc_list[16] = {0}; - - if (!priv->port_up) { - en_dbg(DRV, priv, "stop port called while port already down\n"); - return; - } - -#ifdef CONFIG_DEBUG_FS - mlx4_en_delete_debug_files(priv); -#endif - - /* close port*/ - mlx4_CLOSE_PORT(mdev->dev, priv->port); - - /* Set port as not active */ - priv->port_up = false; - if (priv->counter_index != 0xff) { - mlx4_counter_free(mdev->dev, priv->port, priv->counter_index); - priv->counter_index = 0xff; - } - - /* Promsicuous mode */ - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - priv->flags &= ~(MLX4_EN_FLAG_PROMISC | - MLX4_EN_FLAG_MC_PROMISC); - mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_ALL_DEFAULT); - mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_MC_DEFAULT); - } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { - priv->flags &= ~MLX4_EN_FLAG_PROMISC; - - /* Disable promiscouos mode */ - mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, - priv->port); - - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, - priv->port); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - } - - /* Detach All multicasts */ - memset(&mc_list[10], 0xff, ETH_ALEN); - mc_list[5] = priv->port; /* needed for B0 steering support */ - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, - MLX4_PROT_ETH, priv->broadcast_id); - list_for_each_entry(mclist, &priv->curr_list, list) { - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - mc_list[5] = priv->port; - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, - mc_list, MLX4_PROT_ETH, mclist->reg_id); - } - mlx4_en_clear_list(dev); - list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { - list_del(&mclist->list); - kfree(mclist); - } - - /* Flush multicast filter */ - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); - mlx4_en_destroy_drop_qp(priv); - - /* Free TX Rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[i]); - mlx4_en_deactivate_cq(priv, priv->tx_cq[i]); - } - msleep(10); - - for (i = 0; i < priv->tx_ring_num; i++) - mlx4_en_free_tx_buf(dev, priv->tx_ring[i]); - - /* Free RSS qps */ - mlx4_en_release_rss_steer(priv); - - /* Unregister Mac address for the port */ - mlx4_en_put_qp(priv); - mdev->mac_removed[priv->port] = 1; - - /* Free RX Rings */ - for (i = 0; i < priv->rx_ring_num; i++) { - struct mlx4_en_cq *cq = priv->rx_cq[i]; - mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); - mlx4_en_deactivate_cq(priv, cq); - } - - callout_stop(&priv->watchdog_timer); - - dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -} - -static void mlx4_en_restart(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - watchdog_task); - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - struct mlx4_en_tx_ring *ring; - int i; - - - if (priv->blocked == 0 || priv->port_up == 0) - return; - for (i = 0; i < priv->tx_ring_num; i++) { - ring = priv->tx_ring[i]; - if (ring->blocked && - ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks) - goto reset; - } - return; - -reset: - priv->port_stats.tx_timeout++; - en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); - - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - mlx4_en_stop_port(dev); - //for (i = 0; i < priv->tx_ring_num; i++) - // netdev_tx_reset_queue(priv->tx_ring[i]->tx_queue); - if (mlx4_en_start_port(dev)) - en_err(priv, "Failed restarting port %d\n", priv->port); - } - mutex_unlock(&mdev->state_lock); -} - -static void mlx4_en_clear_stats(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int i; - - if (!mlx4_is_slave(mdev->dev)) - if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - en_dbg(HW, priv, "Failed dumping statistics\n"); - - memset(&priv->pstats, 0, sizeof(priv->pstats)); - memset(&priv->pkstats, 0, sizeof(priv->pkstats)); - memset(&priv->port_stats, 0, sizeof(priv->port_stats)); - memset(&priv->vport_stats, 0, sizeof(priv->vport_stats)); - - for (i = 0; i < priv->tx_ring_num; i++) { - priv->tx_ring[i]->bytes = 0; - priv->tx_ring[i]->packets = 0; - priv->tx_ring[i]->tx_csum = 0; - priv->tx_ring[i]->oversized_packets = 0; - } - for (i = 0; i < priv->rx_ring_num; i++) { - priv->rx_ring[i]->bytes = 0; - priv->rx_ring[i]->packets = 0; - priv->rx_ring[i]->csum_ok = 0; - priv->rx_ring[i]->csum_none = 0; - } -} - -static void mlx4_en_open(void* arg) -{ - - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - struct net_device *dev; - int err = 0; - - priv = arg; - mdev = priv->mdev; - dev = priv->dev; - - - mutex_lock(&mdev->state_lock); - - if (!mdev->device_up) { - en_err(priv, "Cannot open - device down/disabled\n"); - goto out; - } - - /* Reset HW statistics and SW counters */ - mlx4_en_clear_stats(dev); - - err = mlx4_en_start_port(dev); - if (err) - en_err(priv, "Failed starting port:%d\n", priv->port); - -out: - mutex_unlock(&mdev->state_lock); - return; -} - -void mlx4_en_free_resources(struct mlx4_en_priv *priv) -{ - int i; - -#ifdef CONFIG_RFS_ACCEL - if (priv->dev->rx_cpu_rmap) { - free_irq_cpu_rmap(priv->dev->rx_cpu_rmap); - priv->dev->rx_cpu_rmap = NULL; - } -#endif - - for (i = 0; i < priv->tx_ring_num; i++) { - if (priv->tx_ring && priv->tx_ring[i]) - mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); - if (priv->tx_cq && priv->tx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); - } - - for (i = 0; i < priv->rx_ring_num; i++) { - if (priv->rx_ring[i]) - mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], - priv->prof->rx_ring_size, priv->stride); - if (priv->rx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); - } - - if (priv->sysctl) - sysctl_ctx_free(&priv->stat_ctx); -} - -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) -{ - struct mlx4_en_port_profile *prof = priv->prof; - int i; - int node = 0; - - /* Create rx Rings */ - for (i = 0; i < priv->rx_ring_num; i++) { - if (mlx4_en_create_cq(priv, &priv->rx_cq[i], - prof->rx_ring_size, i, RX, node)) - goto err; - - if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], - prof->rx_ring_size, node)) - goto err; - } - - /* Create tx Rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - if (mlx4_en_create_cq(priv, &priv->tx_cq[i], - prof->tx_ring_size, i, TX, node)) - goto err; - - if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], - prof->tx_ring_size, TXBB_SIZE, node, i)) - goto err; - } - -#ifdef CONFIG_RFS_ACCEL - priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num); - if (!priv->dev->rx_cpu_rmap) - goto err; -#endif - /* Re-create stat sysctls in case the number of rings changed. */ - mlx4_en_sysctl_stat(priv); - return 0; - -err: - en_err(priv, "Failed to allocate NIC resources\n"); - for (i = 0; i < priv->rx_ring_num; i++) { - if (priv->rx_ring[i]) - mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], - prof->rx_ring_size, - priv->stride); - if (priv->rx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); - } - for (i = 0; i < priv->tx_ring_num; i++) { - if (priv->tx_ring[i]) - mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); - if (priv->tx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); - } - priv->port_up = false; - return -ENOMEM; -} - -struct en_port_attribute { - struct attribute attr; - ssize_t (*show)(struct en_port *, struct en_port_attribute *, char *buf); - ssize_t (*store)(struct en_port *, struct en_port_attribute *, char *buf, size_t count); -}; - -#define PORT_ATTR_RO(_name) \ -struct en_port_attribute en_port_attr_##_name = __ATTR_RO(_name) - -#define EN_PORT_ATTR(_name, _mode, _show, _store) \ -struct en_port_attribute en_port_attr_##_name = __ATTR(_name, _mode, _show, _store) - -void mlx4_en_destroy_netdev(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - - en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); - - if (priv->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, priv->vlan_attach); - if (priv->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach); - - /* Unregister device - this will close the port if it was up */ - if (priv->registered) { - mutex_lock(&mdev->state_lock); - ether_ifdetach(dev); - mutex_unlock(&mdev->state_lock); - } - - if (priv->allocated) - mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); - - mutex_lock(&mdev->state_lock); - mlx4_en_stop_port(dev); - mutex_unlock(&mdev->state_lock); - - - cancel_delayed_work(&priv->stats_task); - cancel_delayed_work(&priv->service_task); - /* flush any pending task for this netdev */ - flush_workqueue(mdev->workqueue); - callout_drain(&priv->watchdog_timer); - - /* Detach the netdev so tasks would not attempt to access it */ - mutex_lock(&mdev->state_lock); - mdev->pndev[priv->port] = NULL; - mutex_unlock(&mdev->state_lock); - - - mlx4_en_free_resources(priv); - - /* freeing the sysctl conf cannot be called from within mlx4_en_free_resources */ - if (priv->sysctl) - sysctl_ctx_free(&priv->conf_ctx); - - kfree(priv->tx_ring); - kfree(priv->tx_cq); - - kfree(priv); - if_free(dev); - -} - -static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err = 0; - - en_dbg(DRV, priv, "Change MTU called - current:%u new:%u\n", - (unsigned)dev->if_mtu, (unsigned)new_mtu); - - if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { - en_err(priv, "Bad MTU size:%d.\n", new_mtu); - return -EPERM; - } - mutex_lock(&mdev->state_lock); - dev->if_mtu = new_mtu; - if (dev->if_drv_flags & IFF_DRV_RUNNING) { - if (!mdev->device_up) { - /* NIC is probably restarting - let watchdog task reset - * * the port */ - en_dbg(DRV, priv, "Change MTU called with card down!?\n"); - } else { - mlx4_en_stop_port(dev); - err = mlx4_en_start_port(dev); - if (err) { - en_err(priv, "Failed restarting port:%d\n", - priv->port); - queue_work(mdev->workqueue, &priv->watchdog_task); - } - } - } - mutex_unlock(&mdev->state_lock); - return 0; -} - -static int mlx4_en_calc_media(struct mlx4_en_priv *priv) -{ - int trans_type; - int active; - - active = IFM_ETHER; - if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN) - return (active); - active |= IFM_FDX; - trans_type = priv->port_state.transciver; - /* XXX I don't know all of the transceiver values. */ - switch (priv->port_state.link_speed) { - case 1000: - active |= IFM_1000_T; - break; - case 10000: - if (trans_type > 0 && trans_type <= 0xC) - active |= IFM_10G_SR; - else if (trans_type == 0x80 || trans_type == 0) - active |= IFM_10G_CX4; - break; - case 40000: - active |= IFM_40G_CR4; - break; - } - if (priv->prof->tx_pause) - active |= IFM_ETH_TXPAUSE; - if (priv->prof->rx_pause) - active |= IFM_ETH_RXPAUSE; - - return (active); -} - -static void mlx4_en_media_status(struct ifnet *dev, struct ifmediareq *ifmr) -{ - struct mlx4_en_priv *priv; - - priv = dev->if_softc; - ifmr->ifm_status = IFM_AVALID; - if (priv->last_link_state != MLX4_DEV_EVENT_PORT_DOWN) - ifmr->ifm_status |= IFM_ACTIVE; - ifmr->ifm_active = mlx4_en_calc_media(priv); - - return; -} - -static int mlx4_en_media_change(struct ifnet *dev) -{ - struct mlx4_en_priv *priv; - struct ifmedia *ifm; - int rxpause; - int txpause; - int error; - - priv = dev->if_softc; - ifm = &priv->media; - rxpause = txpause = 0; - error = 0; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return (EINVAL); - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - break; - case IFM_10G_SR: - case IFM_10G_CX4: - case IFM_1000_T: - case IFM_40G_CR4: - if ((IFM_SUBTYPE(ifm->ifm_media) - == IFM_SUBTYPE(mlx4_en_calc_media(priv))) - && (ifm->ifm_media & IFM_FDX)) - break; - /* Fallthrough */ - default: - printf("%s: Only auto media type\n", if_name(dev)); - return (EINVAL); - } - /* Allow user to set/clear pause */ - if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) - rxpause = 1; - if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) - txpause = 1; - if (priv->prof->tx_pause != txpause || priv->prof->rx_pause != rxpause) { - priv->prof->tx_pause = txpause; - priv->prof->rx_pause = rxpause; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, priv->prof->tx_pause, - priv->prof->tx_ppp, priv->prof->rx_pause, - priv->prof->rx_ppp); - } - return (error); -} - -static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) -{ - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - struct ifreq *ifr; - int error; - int mask; - - error = 0; - mask = 0; - priv = dev->if_softc; - mdev = priv->mdev; - ifr = (struct ifreq *) data; - switch (command) { - - case SIOCSIFMTU: - error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu); - break; - case SIOCSIFFLAGS: - if (dev->if_flags & IFF_UP) { - if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) { - mutex_lock(&mdev->state_lock); - mlx4_en_start_port(dev); - mutex_unlock(&mdev->state_lock); - } else { - mlx4_en_set_rx_mode(dev); - } - } else { - mutex_lock(&mdev->state_lock); - if (dev->if_drv_flags & IFF_DRV_RUNNING) { - mlx4_en_stop_port(dev); - if_link_state_change(dev, LINK_STATE_DOWN); - } - mutex_unlock(&mdev->state_lock); - } - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - mlx4_en_set_rx_mode(dev); - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - error = ifmedia_ioctl(dev, ifr, &priv->media, command); - break; - case SIOCSIFCAP: - mutex_lock(&mdev->state_lock); - mask = ifr->ifr_reqcap ^ dev->if_capenable; - if (mask & IFCAP_TXCSUM) { - dev->if_capenable ^= IFCAP_TXCSUM; - dev->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); - - if (IFCAP_TSO4 & dev->if_capenable && - !(IFCAP_TXCSUM & dev->if_capenable)) { - dev->if_capenable &= ~IFCAP_TSO4; - dev->if_hwassist &= ~CSUM_IP_TSO; - if_printf(dev, - "tso4 disabled due to -txcsum.\n"); - } - } - if (mask & IFCAP_TXCSUM_IPV6) { - dev->if_capenable ^= IFCAP_TXCSUM_IPV6; - dev->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); - - if (IFCAP_TSO6 & dev->if_capenable && - !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { - dev->if_capenable &= ~IFCAP_TSO6; - dev->if_hwassist &= ~CSUM_IP6_TSO; - if_printf(dev, - "tso6 disabled due to -txcsum6.\n"); - } - } - if (mask & IFCAP_RXCSUM) - dev->if_capenable ^= IFCAP_RXCSUM; - if (mask & IFCAP_RXCSUM_IPV6) - dev->if_capenable ^= IFCAP_RXCSUM_IPV6; - - if (mask & IFCAP_TSO4) { - if (!(IFCAP_TSO4 & dev->if_capenable) && - !(IFCAP_TXCSUM & dev->if_capenable)) { - if_printf(dev, "enable txcsum first.\n"); - error = EAGAIN; - goto out; - } - dev->if_capenable ^= IFCAP_TSO4; - dev->if_hwassist ^= CSUM_IP_TSO; - } - if (mask & IFCAP_TSO6) { - if (!(IFCAP_TSO6 & dev->if_capenable) && - !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { - if_printf(dev, "enable txcsum6 first.\n"); - error = EAGAIN; - goto out; - } - dev->if_capenable ^= IFCAP_TSO6; - dev->if_hwassist ^= CSUM_IP6_TSO; - } - if (mask & IFCAP_LRO) - dev->if_capenable ^= IFCAP_LRO; - if (mask & IFCAP_VLAN_HWTAGGING) - dev->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_VLAN_HWFILTER) - dev->if_capenable ^= IFCAP_VLAN_HWFILTER; - if (mask & IFCAP_WOL_MAGIC) - dev->if_capenable ^= IFCAP_WOL_MAGIC; - if (dev->if_drv_flags & IFF_DRV_RUNNING) - mlx4_en_start_port(dev); -out: - mutex_unlock(&mdev->state_lock); - VLAN_CAPABILITIES(dev); - break; -#if __FreeBSD_version >= 1100036 - case SIOCGI2C: { - struct ifi2creq i2c; - - error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); - if (error) - break; - if (i2c.len > sizeof(i2c.data)) { - error = EINVAL; - break; - } - /* - * Note that we ignore i2c.addr here. The driver hardcodes - * the address to 0x50, while standard expects it to be 0xA0. - */ - error = mlx4_get_module_info(mdev->dev, priv->port, - i2c.offset, i2c.len, i2c.data); - if (error < 0) { - error = -error; - break; - } - error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); - break; - } -#endif - default: - error = ether_ioctl(dev, command, data); - break; - } - - return (error); -} - - -int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, - struct mlx4_en_port_profile *prof) -{ - struct net_device *dev; - struct mlx4_en_priv *priv; - uint8_t dev_addr[ETHER_ADDR_LEN]; - int err; - int i; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - dev = priv->dev = if_alloc(IFT_ETHER); - if (dev == NULL) { - en_err(priv, "Net device allocation failed\n"); - kfree(priv); - return -ENOMEM; - } - dev->if_softc = priv; - if_initname(dev, "mlxen", atomic_fetchadd_int(&mlx4_en_unit, 1)); - dev->if_mtu = ETHERMTU; - dev->if_init = mlx4_en_open; - dev->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - dev->if_ioctl = mlx4_en_ioctl; - dev->if_transmit = mlx4_en_transmit; - dev->if_qflush = mlx4_en_qflush; - dev->if_snd.ifq_maxlen = prof->tx_ring_size; - - /* - * Initialize driver private data - */ - priv->counter_index = 0xff; - spin_lock_init(&priv->stats_lock); - INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); - INIT_WORK(&priv->watchdog_task, mlx4_en_restart); - INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); - INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); - INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); - callout_init(&priv->watchdog_timer, 1); -#ifdef CONFIG_RFS_ACCEL - INIT_LIST_HEAD(&priv->filters); - spin_lock_init(&priv->filters_lock); -#endif - - priv->msg_enable = MLX4_EN_MSG_LEVEL; - priv->dev = dev; - priv->mdev = mdev; - priv->ddev = &mdev->pdev->dev; - priv->prof = prof; - priv->port = port; - priv->port_up = false; - priv->flags = prof->flags; - - priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up; - priv->tx_ring_num = prof->tx_ring_num; - priv->tx_ring = kcalloc(MAX_TX_RINGS, - sizeof(struct mlx4_en_tx_ring *), GFP_KERNEL); - if (!priv->tx_ring) { - err = -ENOMEM; - goto out; - } - priv->tx_cq = kcalloc(sizeof(struct mlx4_en_cq *), MAX_TX_RINGS, - GFP_KERNEL); - if (!priv->tx_cq) { - err = -ENOMEM; - goto out; - } - - priv->rx_ring_num = prof->rx_ring_num; - priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; - priv->mac_index = -1; - priv->last_ifq_jiffies = 0; - priv->if_counters_rx_errors = 0; - priv->if_counters_rx_no_buffer = 0; -#ifdef CONFIG_MLX4_EN_DCB - if (!mlx4_is_slave(priv->mdev->dev)) { - priv->dcbx_cap = DCB_CAP_DCBX_HOST; - priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { - dev->dcbnl_ops = &mlx4_en_dcbnl_ops; - } else { - en_info(priv, "QoS disabled - no HW support\n"); - dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; - } - } -#endif - - for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) - INIT_HLIST_HEAD(&priv->mac_hash[i]); - - /* Query for default mac and max mtu */ - priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; - priv->mac = mdev->dev->caps.def_mac[priv->port]; - if (ILLEGAL_MAC(priv->mac)) { -#if BITS_PER_LONG == 64 - en_err(priv, "Port: %d, invalid mac burned: 0x%lx, quiting\n", - priv->port, priv->mac); -#elif BITS_PER_LONG == 32 - en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", - priv->port, priv->mac); -#endif - err = -EINVAL; - goto out; - } - - priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + - DS_SIZE); - - mlx4_en_sysctl_conf(priv); - - err = mlx4_en_alloc_resources(priv); - if (err) - goto out; - - /* Allocate page for receive rings */ - err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, - MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); - if (err) { - en_err(priv, "Failed to allocate page for rx qps\n"); - goto out; - } - priv->allocated = 1; - - /* - * Set driver features - */ - dev->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6; - dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; - dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER; - dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU; - dev->if_capabilities |= IFCAP_LRO; - dev->if_capabilities |= IFCAP_HWSTATS; - - if (mdev->LSO_support) - dev->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTSO; - -#if __FreeBSD_version >= 1100000 - /* set TSO limits so that we don't have to drop TX packets */ - dev->if_hw_tsomax = MLX4_EN_TX_MAX_PAYLOAD_SIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) /* hdr */; - dev->if_hw_tsomaxsegcount = MLX4_EN_TX_MAX_MBUF_FRAGS - 1 /* hdr */; - dev->if_hw_tsomaxsegsize = MLX4_EN_TX_MAX_MBUF_SIZE; -#endif - - dev->if_capenable = dev->if_capabilities; - - dev->if_hwassist = 0; - if (dev->if_capenable & (IFCAP_TSO4 | IFCAP_TSO6)) - dev->if_hwassist |= CSUM_TSO; - if (dev->if_capenable & IFCAP_TXCSUM) - dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); - if (dev->if_capenable & IFCAP_TXCSUM_IPV6) - dev->if_hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); - - - /* Register for VLAN events */ - priv->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - mlx4_en_vlan_rx_add_vid, priv, EVENTHANDLER_PRI_FIRST); - priv->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - mlx4_en_vlan_rx_kill_vid, priv, EVENTHANDLER_PRI_FIRST); - - mdev->pndev[priv->port] = dev; - - priv->last_link_state = MLX4_DEV_EVENT_PORT_DOWN; - mlx4_en_set_default_moderation(priv); - - /* Set default MAC */ - for (i = 0; i < ETHER_ADDR_LEN; i++) - dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); - - - ether_ifattach(dev, dev_addr); - if_link_state_change(dev, LINK_STATE_DOWN); - ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, - mlx4_en_media_change, mlx4_en_media_status); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_1000_T, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_SR, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_CX4, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_40G_CR4, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); - ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); - - en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - priv->registered = 1; - - en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - - priv->rx_mb_size = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; - err = mlx4_SET_PORT_general(mdev->dev, priv->port, - priv->rx_mb_size, - prof->tx_pause, prof->tx_ppp, - prof->rx_pause, prof->rx_ppp); - if (err) { - en_err(priv, "Failed setting port general configurations " - "for port %d, with error %d\n", priv->port, err); - goto out; - } - - /* Init port */ - en_warn(priv, "Initializing port\n"); - err = mlx4_INIT_PORT(mdev->dev, priv->port); - if (err) { - en_err(priv, "Failed Initializing port\n"); - goto out; - } - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); - - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) - queue_delayed_work(mdev->workqueue, &priv->service_task, SERVICE_TASK_DELAY); - - return 0; - -out: - mlx4_en_destroy_netdev(dev); - return err; -} - -static int mlx4_en_set_ring_size(struct net_device *dev, - int rx_size, int tx_size) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int port_up = 0; - int err = 0; - - rx_size = roundup_pow_of_two(rx_size); - rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); - rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); - tx_size = roundup_pow_of_two(tx_size); - tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); - tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); - - if (rx_size == (priv->port_up ? - priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size) && - tx_size == priv->tx_ring[0]->size) - return 0; - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - port_up = 1; - mlx4_en_stop_port(dev); - } - mlx4_en_free_resources(priv); - priv->prof->tx_ring_size = tx_size; - priv->prof->rx_ring_size = rx_size; - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } - if (port_up) { - err = mlx4_en_start_port(dev); - if (err) - en_err(priv, "Failed starting port\n"); - } -out: - mutex_unlock(&mdev->state_lock); - return err; -} -static int mlx4_en_set_rx_ring_size(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int size; - int error; - - priv = arg1; - size = priv->prof->rx_ring_size; - error = sysctl_handle_int(oidp, &size, 0, req); - if (error || !req->newptr) - return (error); - error = -mlx4_en_set_ring_size(priv->dev, size, - priv->prof->tx_ring_size); - return (error); -} - -static int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int size; - int error; - - priv = arg1; - size = priv->prof->tx_ring_size; - error = sysctl_handle_int(oidp, &size, 0, req); - if (error || !req->newptr) - return (error); - error = -mlx4_en_set_ring_size(priv->dev, priv->prof->rx_ring_size, - size); - - return (error); -} - -static int mlx4_en_get_module_info(struct net_device *dev, - struct ethtool_modinfo *modinfo) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int ret; - u8 data[4]; - - /* Read first 2 bytes to get Module & REV ID */ - ret = mlx4_get_module_info(mdev->dev, priv->port, - 0/*offset*/, 2/*size*/, data); - - if (ret < 2) { - en_err(priv, "Failed to read eeprom module first two bytes, error: 0x%x\n", -ret); - return -EIO; - } - - switch (data[0] /* identifier */) { - case MLX4_MODULE_ID_QSFP: - modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; - break; - case MLX4_MODULE_ID_QSFP_PLUS: - if (data[1] >= 0x3) { /* revision id */ - modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; - } else { - modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; - } - break; - case MLX4_MODULE_ID_QSFP28: - modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; - break; - case MLX4_MODULE_ID_SFP: - modinfo->type = ETH_MODULE_SFF_8472; - modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; - break; - default: - en_err(priv, "mlx4_en_get_module_info : Not recognized cable type\n"); - return -EINVAL; - } - - return 0; -} - -static int mlx4_en_get_module_eeprom(struct net_device *dev, - struct ethtool_eeprom *ee, - u8 *data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int offset = ee->offset; - int i = 0, ret; - - if (ee->len == 0) - return -EINVAL; - - memset(data, 0, ee->len); - - while (i < ee->len) { - en_dbg(DRV, priv, - "mlx4_get_module_info i(%d) offset(%d) len(%d)\n", - i, offset, ee->len - i); - - ret = mlx4_get_module_info(mdev->dev, priv->port, - offset, ee->len - i, data + i); - - if (!ret) /* Done reading */ - return 0; - - if (ret < 0) { - en_err(priv, - "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n", - i, offset, ee->len - i, ret); - return -1; - } - - i += ret; - offset += ret; - } - return 0; -} - -static void mlx4_en_print_eeprom(u8 *data, __u32 len) -{ - int i; - int j = 0; - int row = 0; - const int NUM_OF_BYTES = 16; - - printf("\nOffset\t\tValues\n"); - printf("------\t\t------\n"); - while(row < len){ - printf("0x%04x\t\t",row); - for(i=0; i < NUM_OF_BYTES; i++){ - printf("%02x ", data[j]); - row++; - j++; - } - printf("\n"); - } -} - -/* Read cable EEPROM module information by first inspecting the first - * two bytes to get the length and then read the rest of the information. - * The information is printed to dmesg. */ -static int mlx4_en_read_eeprom(SYSCTL_HANDLER_ARGS) -{ - - u8* data; - int error; - int result = 0; - struct mlx4_en_priv *priv; - struct net_device *dev; - struct ethtool_modinfo modinfo; - struct ethtool_eeprom ee; - - error = sysctl_handle_int(oidp, &result, 0, req); - if (error || !req->newptr) - return (error); - - if (result == 1) { - priv = arg1; - dev = priv->dev; - data = kmalloc(PAGE_SIZE, GFP_KERNEL); - - error = mlx4_en_get_module_info(dev, &modinfo); - if (error) { - en_err(priv, - "mlx4_en_get_module_info returned with error - FAILED (0x%x)\n", - -error); - goto out; - } - - ee.len = modinfo.eeprom_len; - ee.offset = 0; - - error = mlx4_en_get_module_eeprom(dev, &ee, data); - if (error) { - en_err(priv, - "mlx4_en_get_module_eeprom returned with error - FAILED (0x%x)\n", - -error); - /* Continue printing partial information in case of an error */ - } - - /* EEPROM information will be printed in dmesg */ - mlx4_en_print_eeprom(data, ee.len); -out: - kfree(data); - } - /* Return zero to prevent sysctl failure. */ - return (0); -} - -static int mlx4_en_set_tx_ppp(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int ppp; - int error; - - priv = arg1; - ppp = priv->prof->tx_ppp; - error = sysctl_handle_int(oidp, &ppp, 0, req); - if (error || !req->newptr) - return (error); - if (ppp > 0xff || ppp < 0) - return (-EINVAL); - priv->prof->tx_ppp = ppp; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - - return (error); -} - -static int mlx4_en_set_rx_ppp(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - int ppp; - int error; - int port_up; - - port_up = 0; - priv = arg1; - mdev = priv->mdev; - ppp = priv->prof->rx_ppp; - error = sysctl_handle_int(oidp, &ppp, 0, req); - if (error || !req->newptr) - return (error); - if (ppp > 0xff || ppp < 0) - return (-EINVAL); - /* See if we have to change the number of tx queues. */ - if (!ppp != !priv->prof->rx_ppp) { - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - port_up = 1; - mlx4_en_stop_port(priv->dev); - } - mlx4_en_free_resources(priv); - priv->prof->rx_ppp = ppp; - error = -mlx4_en_alloc_resources(priv); - if (error) - en_err(priv, "Failed reallocating port resources\n"); - if (error == 0 && port_up) { - error = -mlx4_en_start_port(priv->dev); - if (error) - en_err(priv, "Failed starting port\n"); - } - mutex_unlock(&mdev->state_lock); - return (error); - - } - priv->prof->rx_ppp = ppp; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - - return (error); -} - -static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) -{ - struct net_device *dev; - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - struct sysctl_oid_list *node_list; - struct sysctl_oid *coal; - struct sysctl_oid_list *coal_list; - const char *pnameunit; - - dev = priv->dev; - ctx = &priv->conf_ctx; - pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); - - sysctl_ctx_init(ctx); - priv->sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), - OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, - "conf", CTLFLAG_RD, NULL, "Configuration"); - node_list = SYSCTL_CHILDREN(node); - - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "msg_enable", - CTLFLAG_RW, &priv->msg_enable, 0, - "Driver message enable bitfield"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_rings", - CTLFLAG_RD, &priv->rx_ring_num, 0, - "Number of receive rings"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_rings", - CTLFLAG_RD, &priv->tx_ring_num, 0, - "Number of transmit rings"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_size", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_rx_ring_size, "I", "Receive ring size"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_size", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_tx_ring_size, "I", "Transmit ring size"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_ppp", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_tx_ppp, "I", "TX Per-priority pause"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_ppp", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_rx_ppp, "I", "RX Per-priority pause"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "port_num", - CTLFLAG_RD, &priv->port, 0, - "Port Number"); - SYSCTL_ADD_STRING(ctx, node_list, OID_AUTO, "device_name", - CTLFLAG_RD, __DECONST(void *, pnameunit), 0, - "PCI device name"); - - /* Add coalescer configuration. */ - coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, - "coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration"); - coal_list = SYSCTL_CHILDREN(coal); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low", - CTLFLAG_RW, &priv->pkt_rate_low, 0, - "Packets per-second for minimum delay"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_low", - CTLFLAG_RW, &priv->rx_usecs_low, 0, - "Minimum RX delay in micro-seconds"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_high", - CTLFLAG_RW, &priv->pkt_rate_high, 0, - "Packets per-second for maximum delay"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_high", - CTLFLAG_RW, &priv->rx_usecs_high, 0, - "Maximum RX delay in micro-seconds"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "sample_interval", - CTLFLAG_RW, &priv->sample_interval, 0, - "adaptive frequency in units of HZ ticks"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal", - CTLFLAG_RW, &priv->adaptive_rx_coal, 0, - "Enable adaptive rx coalescing"); - /* EEPROM support */ - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "eeprom_info", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_read_eeprom, "I", "EEPROM information"); -} - -static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) -{ - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - struct sysctl_oid_list *node_list; - struct sysctl_oid *ring_node; - struct sysctl_oid_list *ring_list; - struct mlx4_en_tx_ring *tx_ring; - struct mlx4_en_rx_ring *rx_ring; - char namebuf[128]; - int i; - - ctx = &priv->stat_ctx; - sysctl_ctx_init(ctx); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, - "stat", CTLFLAG_RD, NULL, "Statistics"); - node_list = SYSCTL_CHILDREN(node); - -#ifdef MLX4_EN_PERF_STAT - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, - &priv->pstats.tx_poll, "TX Poll calls"); - SYSCTL_ADD_QUAD(ctx, node_list, OID_AUTO, "tx_pktsz_avg", CTLFLAG_RD, - &priv->pstats.tx_pktsz_avg, "TX average packet size"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "inflight_avg", CTLFLAG_RD, - &priv->pstats.inflight_avg, "TX average packets in-flight"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_coal_avg", CTLFLAG_RD, - &priv->pstats.tx_coal_avg, "TX average coalesced completions"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_coal_avg", CTLFLAG_RD, - &priv->pstats.rx_coal_avg, "RX average coalesced completions"); -#endif - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tso_packets", CTLFLAG_RD, - &priv->port_stats.tso_packets, "TSO packets sent"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "queue_stopped", CTLFLAG_RD, - &priv->port_stats.queue_stopped, "Queue full"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "wake_queue", CTLFLAG_RD, - &priv->port_stats.wake_queue, "Queue resumed after full"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD, - &priv->port_stats.tx_timeout, "Transmit timeouts"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_oversized_packets", CTLFLAG_RD, - &priv->port_stats.oversized_packets, "TX oversized packets, m_defrag failed"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD, - &priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD, - &priv->port_stats.rx_chksum_good, "RX checksum offload success"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_none", CTLFLAG_RD, - &priv->port_stats.rx_chksum_none, "RX without checksum offload"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_chksum_offload", - CTLFLAG_RD, &priv->port_stats.tx_chksum_offload, - "TX checksum offloads"); - - /* Could strdup the names and add in a loop. This is simpler. */ - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_bytes", CTLFLAG_RD, - &priv->pkstats.rx_bytes, "RX Bytes"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_packets", CTLFLAG_RD, - &priv->pkstats.rx_packets, "RX packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_multicast_packets", CTLFLAG_RD, - &priv->pkstats.rx_multicast_packets, "RX Multicast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_broadcast_packets", CTLFLAG_RD, - &priv->pkstats.rx_broadcast_packets, "RX Broadcast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_errors", CTLFLAG_RD, - &priv->pkstats.rx_errors, "RX Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_dropped", CTLFLAG_RD, - &priv->pkstats.rx_dropped, "RX Dropped"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_length_errors", CTLFLAG_RD, - &priv->pkstats.rx_length_errors, "RX Length Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_over_errors", CTLFLAG_RD, - &priv->pkstats.rx_over_errors, "RX Over Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_crc_errors", CTLFLAG_RD, - &priv->pkstats.rx_crc_errors, "RX CRC Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_jabbers", CTLFLAG_RD, - &priv->pkstats.rx_jabbers, "RX Jabbers"); - - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_in_range_length_error", CTLFLAG_RD, - &priv->pkstats.rx_in_range_length_error, "RX IN_Range Length Error"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_out_range_length_error", - CTLFLAG_RD, &priv->pkstats.rx_out_range_length_error, - "RX Out Range Length Error"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_lt_64_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_lt_64_bytes_packets, "RX Lt 64 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_127_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_127_bytes_packets, "RX 127 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_255_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_255_bytes_packets, "RX 255 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_511_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_511_bytes_packets, "RX 511 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1023_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1023_bytes_packets, "RX 1023 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1518_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1518_bytes_packets, "RX 1518 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1522_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1522_bytes_packets, "RX 1522 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1548_bytes_packets, "RX 1548 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_gt_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_gt_1548_bytes_packets, - "RX Greater Then 1548 bytes Packets"); - -struct mlx4_en_pkt_stats { - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; - unsigned long tx_dropped; - unsigned long tx_lt_64_bytes_packets; - unsigned long tx_127_bytes_packets; - unsigned long tx_255_bytes_packets; - unsigned long tx_511_bytes_packets; - unsigned long tx_1023_bytes_packets; - unsigned long tx_1518_bytes_packets; - unsigned long tx_1522_bytes_packets; - unsigned long tx_1548_bytes_packets; - unsigned long tx_gt_1548_bytes_packets; - unsigned long rx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; - unsigned long tx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; -#define NUM_PKT_STATS 72 -}; - - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_packets", CTLFLAG_RD, - &priv->pkstats.tx_packets, "TX packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_bytes", CTLFLAG_RD, - &priv->pkstats.tx_bytes, "TX Bytes"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_multicast_packets", CTLFLAG_RD, - &priv->pkstats.tx_multicast_packets, "TX Multicast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_broadcast_packets", CTLFLAG_RD, - &priv->pkstats.tx_broadcast_packets, "TX Broadcast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_errors", CTLFLAG_RD, - &priv->pkstats.tx_errors, "TX Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_dropped", CTLFLAG_RD, - &priv->pkstats.tx_dropped, "TX Dropped"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_lt_64_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_lt_64_bytes_packets, "TX Less Then 64 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_127_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_127_bytes_packets, "TX 127 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_255_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_255_bytes_packets, "TX 255 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_511_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_511_bytes_packets, "TX 511 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1023_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1023_bytes_packets, "TX 1023 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1518_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1518_bytes_packets, "TX 1518 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1522_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1522_bytes_packets, "TX 1522 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1548_bytes_packets, "TX 1548 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_gt_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_gt_1548_bytes_packets, - "TX Greater Then 1548 Bytes Packets"); - - - - for (i = 0; i < priv->tx_ring_num; i++) { - tx_ring = priv->tx_ring[i]; - snprintf(namebuf, sizeof(namebuf), "tx_ring%d", i); - ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "TX Ring"); - ring_list = SYSCTL_CHILDREN(ring_node); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", - CTLFLAG_RD, &tx_ring->packets, "TX packets"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", - CTLFLAG_RD, &tx_ring->bytes, "TX bytes"); - } - - for (i = 0; i < priv->rx_ring_num; i++) { - rx_ring = priv->rx_ring[i]; - snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i); - ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "RX Ring"); - ring_list = SYSCTL_CHILDREN(ring_node); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", - CTLFLAG_RD, &rx_ring->packets, "RX packets"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", - CTLFLAG_RD, &rx_ring->bytes, "RX bytes"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", - CTLFLAG_RD, &rx_ring->errors, "RX soft errors"); - } -} diff --git a/sys/ofed/drivers/net/mlx4/en_port.c b/sys/ofed/drivers/net/mlx4/en_port.c deleted file mode 100644 index 2a1c4ba406a9..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_port.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <sys/types.h> -#include <linux/if_vlan.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> - -#include "en_port.h" -#include "mlx4_en.h" -#define EN_IFQ_MIN_INTERVAL 3000 - - -int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_vlan_fltr_mbox *filter; - int i; - int j; - int index = 0; - u32 entry; - int err = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - filter = mailbox->buf; - memset(filter, 0, sizeof(*filter)); - for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) { - entry = 0; - for (j = 0; j < 32; j++) { - if (test_bit(index, priv->active_vlans)) - entry |= 1 << j; - index++; - } - filter->entry[i] = cpu_to_be32(entry); - } - err = mlx4_cmd(dev, mailbox->dma, priv->port, 0, MLX4_CMD_SET_VLAN_FLTR, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port) -{ - struct mlx4_en_query_port_context *qport_context; - struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); - struct mlx4_en_port_state *state = &priv->port_state; - struct mlx4_cmd_mailbox *mailbox; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - memset(mailbox->buf, 0, sizeof(*qport_context)); - err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - goto out; - qport_context = mailbox->buf; - - /* This command is always accessed from Ethtool context - * already synchronized, no need in locking */ - state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK); - switch (qport_context->link_speed & MLX4_EN_SPEED_MASK) { - case MLX4_EN_1G_SPEED: - state->link_speed = 1000; - break; - case MLX4_EN_10G_SPEED_XAUI: - case MLX4_EN_10G_SPEED_XFI: - state->link_speed = 10000; - break; - case MLX4_EN_20G_SPEED: - state->link_speed = 20000; - break; - case MLX4_EN_40G_SPEED: - state->link_speed = 40000; - break; - case MLX4_EN_56G_SPEED: - state->link_speed = 56000; - break; - default: - state->link_speed = -1; - break; - } - state->transciver = qport_context->transceiver; - state->autoneg = !!(qport_context->autoneg & MLX4_EN_AUTONEG_MASK); - -out: - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - return err; -} - -int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) -{ - struct mlx4_en_stat_out_mbox *mlx4_en_stats; - struct mlx4_en_stat_out_flow_control_mbox *flowstats; - struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); - struct mlx4_en_vport_stats *vport_stats = &priv->vport_stats; - struct mlx4_cmd_mailbox *mailbox = NULL; - struct mlx4_cmd_mailbox *mailbox_flow = NULL; - u64 in_mod = reset << 8 | port; - int err; - int i; - int do_if_stat = 1; - unsigned long period = (unsigned long) (jiffies - priv->last_ifq_jiffies); - struct mlx4_en_vport_stats tmp_vport_stats; - struct net_device *dev; - - if (jiffies_to_msecs(period) < EN_IFQ_MIN_INTERVAL || - priv->counter_index == 0xff) - do_if_stat = 0; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto mailbox_out; - } - - mailbox_flow = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox_flow)) { - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - err = PTR_ERR(mailbox_flow); - goto mailbox_out; - } - - /* 0xffs indicates invalid value */ - memset(mailbox_flow->buf, 0xff, sizeof(*flowstats) * - MLX4_NUM_PRIORITIES); - - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) { - memset(mailbox_flow->buf, 0, sizeof(*flowstats)); - err = mlx4_cmd_box(mdev->dev, 0, mailbox_flow->dma, - in_mod | 1<<12, 0, MLX4_CMD_DUMP_ETH_STATS, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - if (err) - goto out; - } - - err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0, - MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (err) - goto out; - - mlx4_en_stats = mailbox->buf; - - spin_lock(&priv->stats_lock); - - priv->port_stats.rx_chksum_good = 0; - priv->port_stats.rx_chksum_none = 0; - for (i = 0; i < priv->rx_ring_num; i++) { - priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok; - priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none; - } - - priv->port_stats.tx_chksum_offload = 0; - priv->port_stats.queue_stopped = 0; - priv->port_stats.wake_queue = 0; - for (i = 0; i < priv->tx_ring_num; i++) { - priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum; - priv->port_stats.queue_stopped += priv->tx_ring[i]->queue_stopped; - priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue; - priv->port_stats.oversized_packets += priv->tx_ring[i]->oversized_packets; - } - /* RX Statistics */ - priv->pkstats.rx_packets = be64_to_cpu(mlx4_en_stats->RTOT_prio_0) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_1) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_2) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_3) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_4) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_5) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_6) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_7) + - be64_to_cpu(mlx4_en_stats->RTOT_novlan); - priv->pkstats.rx_bytes = be64_to_cpu(mlx4_en_stats->ROCT_prio_0) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_1) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_2) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_3) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_4) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_5) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_6) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_7) + - be64_to_cpu(mlx4_en_stats->ROCT_novlan); - priv->pkstats.rx_multicast_packets = be64_to_cpu(mlx4_en_stats->MCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->MCAST_novlan); - priv->pkstats.rx_broadcast_packets = be64_to_cpu(mlx4_en_stats->RBCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->RBCAST_novlan); - priv->pkstats.rx_errors = be64_to_cpu(mlx4_en_stats->PCS) + - be32_to_cpu(mlx4_en_stats->RJBBR) + - be32_to_cpu(mlx4_en_stats->RCRC) + - be32_to_cpu(mlx4_en_stats->RRUNT) + - be64_to_cpu(mlx4_en_stats->RInRangeLengthErr) + - be64_to_cpu(mlx4_en_stats->ROutRangeLengthErr) + - be32_to_cpu(mlx4_en_stats->RSHORT) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_0) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_1) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_2) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_3) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_4) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_5) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_6) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_7) + - be64_to_cpu(mlx4_en_stats->RGIANT_novlan); - priv->pkstats.rx_dropped = be32_to_cpu(mlx4_en_stats->RdropOvflw); - priv->pkstats.rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength); - priv->pkstats.rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); - priv->pkstats.rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC); - priv->pkstats.rx_jabbers = be32_to_cpu(mlx4_en_stats->RJBBR); - priv->pkstats.rx_in_range_length_error = be64_to_cpu(mlx4_en_stats->RInRangeLengthErr); - priv->pkstats.rx_out_range_length_error = be64_to_cpu(mlx4_en_stats->ROutRangeLengthErr); - priv->pkstats.rx_lt_64_bytes_packets = be64_to_cpu(mlx4_en_stats->R64_prio_0) + - be64_to_cpu(mlx4_en_stats->R64_prio_1) + - be64_to_cpu(mlx4_en_stats->R64_prio_2) + - be64_to_cpu(mlx4_en_stats->R64_prio_3) + - be64_to_cpu(mlx4_en_stats->R64_prio_4) + - be64_to_cpu(mlx4_en_stats->R64_prio_5) + - be64_to_cpu(mlx4_en_stats->R64_prio_6) + - be64_to_cpu(mlx4_en_stats->R64_prio_7) + - be64_to_cpu(mlx4_en_stats->R64_novlan); - priv->pkstats.rx_127_bytes_packets = be64_to_cpu(mlx4_en_stats->R127_prio_0) + - be64_to_cpu(mlx4_en_stats->R127_prio_1) + - be64_to_cpu(mlx4_en_stats->R127_prio_2) + - be64_to_cpu(mlx4_en_stats->R127_prio_3) + - be64_to_cpu(mlx4_en_stats->R127_prio_4) + - be64_to_cpu(mlx4_en_stats->R127_prio_5) + - be64_to_cpu(mlx4_en_stats->R127_prio_6) + - be64_to_cpu(mlx4_en_stats->R127_prio_7) + - be64_to_cpu(mlx4_en_stats->R127_novlan); - priv->pkstats.rx_255_bytes_packets = be64_to_cpu(mlx4_en_stats->R255_prio_0) + - be64_to_cpu(mlx4_en_stats->R255_prio_1) + - be64_to_cpu(mlx4_en_stats->R255_prio_2) + - be64_to_cpu(mlx4_en_stats->R255_prio_3) + - be64_to_cpu(mlx4_en_stats->R255_prio_4) + - be64_to_cpu(mlx4_en_stats->R255_prio_5) + - be64_to_cpu(mlx4_en_stats->R255_prio_6) + - be64_to_cpu(mlx4_en_stats->R255_prio_7) + - be64_to_cpu(mlx4_en_stats->R255_novlan); - priv->pkstats.rx_511_bytes_packets = be64_to_cpu(mlx4_en_stats->R511_prio_0) + - be64_to_cpu(mlx4_en_stats->R511_prio_1) + - be64_to_cpu(mlx4_en_stats->R511_prio_2) + - be64_to_cpu(mlx4_en_stats->R511_prio_3) + - be64_to_cpu(mlx4_en_stats->R511_prio_4) + - be64_to_cpu(mlx4_en_stats->R511_prio_5) + - be64_to_cpu(mlx4_en_stats->R511_prio_6) + - be64_to_cpu(mlx4_en_stats->R511_prio_7) + - be64_to_cpu(mlx4_en_stats->R511_novlan); - priv->pkstats.rx_1023_bytes_packets = be64_to_cpu(mlx4_en_stats->R1023_prio_0) + - be64_to_cpu(mlx4_en_stats->R1023_prio_1) + - be64_to_cpu(mlx4_en_stats->R1023_prio_2) + - be64_to_cpu(mlx4_en_stats->R1023_prio_3) + - be64_to_cpu(mlx4_en_stats->R1023_prio_4) + - be64_to_cpu(mlx4_en_stats->R1023_prio_5) + - be64_to_cpu(mlx4_en_stats->R1023_prio_6) + - be64_to_cpu(mlx4_en_stats->R1023_prio_7) + - be64_to_cpu(mlx4_en_stats->R1023_novlan); - priv->pkstats.rx_1518_bytes_packets = be64_to_cpu(mlx4_en_stats->R1518_prio_0) + - be64_to_cpu(mlx4_en_stats->R1518_prio_1) + - be64_to_cpu(mlx4_en_stats->R1518_prio_2) + - be64_to_cpu(mlx4_en_stats->R1518_prio_3) + - be64_to_cpu(mlx4_en_stats->R1518_prio_4) + - be64_to_cpu(mlx4_en_stats->R1518_prio_5) + - be64_to_cpu(mlx4_en_stats->R1518_prio_6) + - be64_to_cpu(mlx4_en_stats->R1518_prio_7) + - be64_to_cpu(mlx4_en_stats->R1518_novlan); - priv->pkstats.rx_1522_bytes_packets = be64_to_cpu(mlx4_en_stats->R1522_prio_0) + - be64_to_cpu(mlx4_en_stats->R1522_prio_1) + - be64_to_cpu(mlx4_en_stats->R1522_prio_2) + - be64_to_cpu(mlx4_en_stats->R1522_prio_3) + - be64_to_cpu(mlx4_en_stats->R1522_prio_4) + - be64_to_cpu(mlx4_en_stats->R1522_prio_5) + - be64_to_cpu(mlx4_en_stats->R1522_prio_6) + - be64_to_cpu(mlx4_en_stats->R1522_prio_7) + - be64_to_cpu(mlx4_en_stats->R1522_novlan); - priv->pkstats.rx_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->R1548_prio_0) + - be64_to_cpu(mlx4_en_stats->R1548_prio_1) + - be64_to_cpu(mlx4_en_stats->R1548_prio_2) + - be64_to_cpu(mlx4_en_stats->R1548_prio_3) + - be64_to_cpu(mlx4_en_stats->R1548_prio_4) + - be64_to_cpu(mlx4_en_stats->R1548_prio_5) + - be64_to_cpu(mlx4_en_stats->R1548_prio_6) + - be64_to_cpu(mlx4_en_stats->R1548_prio_7) + - be64_to_cpu(mlx4_en_stats->R1548_novlan); - priv->pkstats.rx_gt_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->R2MTU_prio_0) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_1) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_2) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_3) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_4) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_5) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_6) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_7) + - be64_to_cpu(mlx4_en_stats->R2MTU_novlan); - - /* Tx Stats */ - priv->pkstats.tx_packets = be64_to_cpu(mlx4_en_stats->TTOT_prio_0) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_1) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_2) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_3) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_4) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_5) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_6) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_7) + - be64_to_cpu(mlx4_en_stats->TTOT_novlan); - priv->pkstats.tx_bytes = be64_to_cpu(mlx4_en_stats->TOCT_prio_0) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_1) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_2) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_3) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_4) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_5) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_6) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_7) + - be64_to_cpu(mlx4_en_stats->TOCT_novlan); - priv->pkstats.tx_multicast_packets = be64_to_cpu(mlx4_en_stats->TMCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->TMCAST_novlan); - priv->pkstats.tx_broadcast_packets = be64_to_cpu(mlx4_en_stats->TBCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->TBCAST_novlan); - priv->pkstats.tx_errors = be64_to_cpu(mlx4_en_stats->TGIANT_prio_0) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_1) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_2) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_3) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_4) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_5) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_6) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_7) + - be64_to_cpu(mlx4_en_stats->TGIANT_novlan); - priv->pkstats.tx_dropped = be32_to_cpu(mlx4_en_stats->TDROP) - - priv->pkstats.tx_errors; - priv->pkstats.tx_lt_64_bytes_packets = be64_to_cpu(mlx4_en_stats->T64_prio_0) + - be64_to_cpu(mlx4_en_stats->T64_prio_1) + - be64_to_cpu(mlx4_en_stats->T64_prio_2) + - be64_to_cpu(mlx4_en_stats->T64_prio_3) + - be64_to_cpu(mlx4_en_stats->T64_prio_4) + - be64_to_cpu(mlx4_en_stats->T64_prio_5) + - be64_to_cpu(mlx4_en_stats->T64_prio_6) + - be64_to_cpu(mlx4_en_stats->T64_prio_7) + - be64_to_cpu(mlx4_en_stats->T64_novlan); - priv->pkstats.tx_127_bytes_packets = be64_to_cpu(mlx4_en_stats->T127_prio_0) + - be64_to_cpu(mlx4_en_stats->T127_prio_1) + - be64_to_cpu(mlx4_en_stats->T127_prio_2) + - be64_to_cpu(mlx4_en_stats->T127_prio_3) + - be64_to_cpu(mlx4_en_stats->T127_prio_4) + - be64_to_cpu(mlx4_en_stats->T127_prio_5) + - be64_to_cpu(mlx4_en_stats->T127_prio_6) + - be64_to_cpu(mlx4_en_stats->T127_prio_7) + - be64_to_cpu(mlx4_en_stats->T127_novlan); - priv->pkstats.tx_255_bytes_packets = be64_to_cpu(mlx4_en_stats->T255_prio_0) + - be64_to_cpu(mlx4_en_stats->T255_prio_1) + - be64_to_cpu(mlx4_en_stats->T255_prio_2) + - be64_to_cpu(mlx4_en_stats->T255_prio_3) + - be64_to_cpu(mlx4_en_stats->T255_prio_4) + - be64_to_cpu(mlx4_en_stats->T255_prio_5) + - be64_to_cpu(mlx4_en_stats->T255_prio_6) + - be64_to_cpu(mlx4_en_stats->T255_prio_7) + - be64_to_cpu(mlx4_en_stats->T255_novlan); - priv->pkstats.tx_511_bytes_packets = be64_to_cpu(mlx4_en_stats->T511_prio_0) + - be64_to_cpu(mlx4_en_stats->T511_prio_1) + - be64_to_cpu(mlx4_en_stats->T511_prio_2) + - be64_to_cpu(mlx4_en_stats->T511_prio_3) + - be64_to_cpu(mlx4_en_stats->T511_prio_4) + - be64_to_cpu(mlx4_en_stats->T511_prio_5) + - be64_to_cpu(mlx4_en_stats->T511_prio_6) + - be64_to_cpu(mlx4_en_stats->T511_prio_7) + - be64_to_cpu(mlx4_en_stats->T511_novlan); - priv->pkstats.tx_1023_bytes_packets = be64_to_cpu(mlx4_en_stats->T1023_prio_0) + - be64_to_cpu(mlx4_en_stats->T1023_prio_1) + - be64_to_cpu(mlx4_en_stats->T1023_prio_2) + - be64_to_cpu(mlx4_en_stats->T1023_prio_3) + - be64_to_cpu(mlx4_en_stats->T1023_prio_4) + - be64_to_cpu(mlx4_en_stats->T1023_prio_5) + - be64_to_cpu(mlx4_en_stats->T1023_prio_6) + - be64_to_cpu(mlx4_en_stats->T1023_prio_7) + - be64_to_cpu(mlx4_en_stats->T1023_novlan); - priv->pkstats.tx_1518_bytes_packets = be64_to_cpu(mlx4_en_stats->T1518_prio_0) + - be64_to_cpu(mlx4_en_stats->T1518_prio_1) + - be64_to_cpu(mlx4_en_stats->T1518_prio_2) + - be64_to_cpu(mlx4_en_stats->T1518_prio_3) + - be64_to_cpu(mlx4_en_stats->T1518_prio_4) + - be64_to_cpu(mlx4_en_stats->T1518_prio_5) + - be64_to_cpu(mlx4_en_stats->T1518_prio_6) + - be64_to_cpu(mlx4_en_stats->T1518_prio_7) + - be64_to_cpu(mlx4_en_stats->T1518_novlan); - priv->pkstats.tx_1522_bytes_packets = be64_to_cpu(mlx4_en_stats->T1522_prio_0) + - be64_to_cpu(mlx4_en_stats->T1522_prio_1) + - be64_to_cpu(mlx4_en_stats->T1522_prio_2) + - be64_to_cpu(mlx4_en_stats->T1522_prio_3) + - be64_to_cpu(mlx4_en_stats->T1522_prio_4) + - be64_to_cpu(mlx4_en_stats->T1522_prio_5) + - be64_to_cpu(mlx4_en_stats->T1522_prio_6) + - be64_to_cpu(mlx4_en_stats->T1522_prio_7) + - be64_to_cpu(mlx4_en_stats->T1522_novlan); - priv->pkstats.tx_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->T1548_prio_0) + - be64_to_cpu(mlx4_en_stats->T1548_prio_1) + - be64_to_cpu(mlx4_en_stats->T1548_prio_2) + - be64_to_cpu(mlx4_en_stats->T1548_prio_3) + - be64_to_cpu(mlx4_en_stats->T1548_prio_4) + - be64_to_cpu(mlx4_en_stats->T1548_prio_5) + - be64_to_cpu(mlx4_en_stats->T1548_prio_6) + - be64_to_cpu(mlx4_en_stats->T1548_prio_7) + - be64_to_cpu(mlx4_en_stats->T1548_novlan); - priv->pkstats.tx_gt_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->T2MTU_prio_0) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_1) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_2) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_3) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_4) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_5) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_6) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_7) + - be64_to_cpu(mlx4_en_stats->T2MTU_novlan); - - priv->pkstats.rx_prio[0][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_0); - priv->pkstats.rx_prio[0][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_0); - priv->pkstats.rx_prio[1][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_1); - priv->pkstats.rx_prio[1][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_1); - priv->pkstats.rx_prio[2][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_2); - priv->pkstats.rx_prio[2][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_2); - priv->pkstats.rx_prio[3][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_3); - priv->pkstats.rx_prio[3][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_3); - priv->pkstats.rx_prio[4][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_4); - priv->pkstats.rx_prio[4][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_4); - priv->pkstats.rx_prio[5][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_5); - priv->pkstats.rx_prio[5][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_5); - priv->pkstats.rx_prio[6][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_6); - priv->pkstats.rx_prio[6][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_6); - priv->pkstats.rx_prio[7][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_7); - priv->pkstats.rx_prio[7][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_7); - priv->pkstats.rx_prio[8][0] = be64_to_cpu(mlx4_en_stats->RTOT_novlan); - priv->pkstats.rx_prio[8][1] = be64_to_cpu(mlx4_en_stats->ROCT_novlan); - priv->pkstats.tx_prio[0][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_0); - priv->pkstats.tx_prio[0][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_0); - priv->pkstats.tx_prio[1][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_1); - priv->pkstats.tx_prio[1][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_1); - priv->pkstats.tx_prio[2][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_2); - priv->pkstats.tx_prio[2][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_2); - priv->pkstats.tx_prio[3][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_3); - priv->pkstats.tx_prio[3][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_3); - priv->pkstats.tx_prio[4][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_4); - priv->pkstats.tx_prio[4][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_4); - priv->pkstats.tx_prio[5][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_5); - priv->pkstats.tx_prio[5][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_5); - priv->pkstats.tx_prio[6][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_6); - priv->pkstats.tx_prio[6][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_6); - priv->pkstats.tx_prio[7][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_7); - priv->pkstats.tx_prio[7][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_7); - priv->pkstats.tx_prio[8][0] = be64_to_cpu(mlx4_en_stats->TTOT_novlan); - priv->pkstats.tx_prio[8][1] = be64_to_cpu(mlx4_en_stats->TOCT_novlan); - - flowstats = mailbox_flow->buf; - - for (i = 0; i < MLX4_NUM_PRIORITIES; i++) { - priv->flowstats[i].rx_pause = - be64_to_cpu(flowstats[i].rx_pause); - priv->flowstats[i].rx_pause_duration = - be64_to_cpu(flowstats[i].rx_pause_duration); - priv->flowstats[i].rx_pause_transition = - be64_to_cpu(flowstats[i].rx_pause_transition); - priv->flowstats[i].tx_pause = - be64_to_cpu(flowstats[i].tx_pause); - priv->flowstats[i].tx_pause_duration = - be64_to_cpu(flowstats[i].tx_pause_duration); - priv->flowstats[i].tx_pause_transition = - be64_to_cpu(flowstats[i].tx_pause_transition); - } - - memset(&tmp_vport_stats, 0, sizeof(tmp_vport_stats)); - spin_unlock(&priv->stats_lock); - err = mlx4_get_vport_ethtool_stats(mdev->dev, port, - &tmp_vport_stats, reset); - spin_lock(&priv->stats_lock); - if (!err) { - /* ethtool stats format */ - vport_stats->rx_unicast_packets = tmp_vport_stats.rx_unicast_packets; - vport_stats->rx_unicast_bytes = tmp_vport_stats.rx_unicast_bytes; - vport_stats->rx_multicast_packets = tmp_vport_stats.rx_multicast_packets; - vport_stats->rx_multicast_bytes = tmp_vport_stats.rx_multicast_bytes; - vport_stats->rx_broadcast_packets = tmp_vport_stats.rx_broadcast_packets; - vport_stats->rx_broadcast_bytes = tmp_vport_stats.rx_broadcast_bytes; - vport_stats->rx_dropped = tmp_vport_stats.rx_dropped; - vport_stats->rx_errors = tmp_vport_stats.rx_errors; - vport_stats->tx_unicast_packets = tmp_vport_stats.tx_unicast_packets; - vport_stats->tx_unicast_bytes = tmp_vport_stats.tx_unicast_bytes; - vport_stats->tx_multicast_packets = tmp_vport_stats.tx_multicast_packets; - vport_stats->tx_multicast_bytes = tmp_vport_stats.tx_multicast_bytes; - vport_stats->tx_broadcast_packets = tmp_vport_stats.tx_broadcast_packets; - vport_stats->tx_broadcast_bytes = tmp_vport_stats.tx_broadcast_bytes; - vport_stats->tx_errors = tmp_vport_stats.tx_errors; - } - - if (!mlx4_is_mfunc(mdev->dev)) { -/* netdevice stats format */ -#if __FreeBSD_version >= 1100000 - if (reset == 0) { - dev = mdev->pndev[port]; - if_inc_counter(dev, IFCOUNTER_IPACKETS, - priv->pkstats.rx_packets - priv->pkstats_last.rx_packets); - if_inc_counter(dev, IFCOUNTER_OPACKETS, - priv->pkstats.tx_packets - priv->pkstats_last.tx_packets); - if_inc_counter(dev, IFCOUNTER_IBYTES, - priv->pkstats.rx_bytes - priv->pkstats_last.rx_bytes); - if_inc_counter(dev, IFCOUNTER_OBYTES, - priv->pkstats.tx_bytes - priv->pkstats_last.tx_bytes); - if_inc_counter(dev, IFCOUNTER_IERRORS, - priv->pkstats.rx_errors - priv->pkstats_last.rx_errors); - if_inc_counter(dev, IFCOUNTER_IQDROPS, - priv->pkstats.rx_dropped - priv->pkstats_last.rx_dropped); - if_inc_counter(dev, IFCOUNTER_IMCASTS, - priv->pkstats.rx_multicast_packets - priv->pkstats_last.rx_multicast_packets); - if_inc_counter(dev, IFCOUNTER_OMCASTS, - priv->pkstats.tx_multicast_packets - priv->pkstats_last.tx_multicast_packets); - } - priv->pkstats_last = priv->pkstats; -#else - dev = mdev->pndev[port]; - dev->if_ipackets = priv->pkstats.rx_packets; - dev->if_opackets = priv->pkstats.tx_packets; - dev->if_ibytes = priv->pkstats.rx_bytes; - dev->if_obytes = priv->pkstats.tx_bytes; - dev->if_ierrors = priv->pkstats.rx_errors; - dev->if_iqdrops = priv->pkstats.rx_dropped; - dev->if_imcasts = priv->pkstats.rx_multicast_packets; - dev->if_omcasts = priv->pkstats.tx_multicast_packets; - dev->if_collisions = 0; -#endif - } - - spin_unlock(&priv->stats_lock); - -out: - mlx4_free_cmd_mailbox(mdev->dev, mailbox_flow); - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - -mailbox_out: - if (do_if_stat) - priv->last_ifq_jiffies = jiffies; - - return err; -} diff --git a/sys/ofed/drivers/net/mlx4/en_port.h b/sys/ofed/drivers/net/mlx4/en_port.h deleted file mode 100644 index 6301717e1814..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_port.h +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef _MLX4_EN_PORT_H_ -#define _MLX4_EN_PORT_H_ - - -#define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_SHIFT 31 -#define SET_PORT_MC_PROMISC_SHIFT 30 - -#define MLX4_EN_NUM_TC 8 - -#define VLAN_FLTR_SIZE 128 -struct mlx4_set_vlan_fltr_mbox { - __be32 entry[VLAN_FLTR_SIZE]; -}; - - -enum { - MLX4_MCAST_CONFIG = 0, - MLX4_MCAST_DISABLE = 1, - MLX4_MCAST_ENABLE = 2, -}; - -enum { - MLX4_EN_10G_SPEED_XAUI = 0x00, - MLX4_EN_10G_SPEED_XFI = 0x01, - MLX4_EN_1G_SPEED = 0x02, - MLX4_EN_20G_SPEED = 0x08, - MLX4_EN_40G_SPEED = 0x40, - MLX4_EN_56G_SPEED = 0x20, - MLX4_EN_OTHER_SPEED = 0x0f, -}; - -struct mlx4_en_query_port_context { - u8 link_up; -#define MLX4_EN_LINK_UP_MASK 0x80 - u8 autoneg; -#define MLX4_EN_AUTONEG_MASK 0x80 - __be16 mtu; - u8 reserved2; - u8 link_speed; -#define MLX4_EN_SPEED_MASK 0x6b - u16 reserved3[5]; - __be64 mac; - u8 transceiver; -}; - - -struct mlx4_en_stat_out_mbox { - /* Received frames with a length of 64 octets */ - __be64 R64_prio_0; - __be64 R64_prio_1; - __be64 R64_prio_2; - __be64 R64_prio_3; - __be64 R64_prio_4; - __be64 R64_prio_5; - __be64 R64_prio_6; - __be64 R64_prio_7; - __be64 R64_novlan; - /* Received frames with a length of 127 octets */ - __be64 R127_prio_0; - __be64 R127_prio_1; - __be64 R127_prio_2; - __be64 R127_prio_3; - __be64 R127_prio_4; - __be64 R127_prio_5; - __be64 R127_prio_6; - __be64 R127_prio_7; - __be64 R127_novlan; - /* Received frames with a length of 255 octets */ - __be64 R255_prio_0; - __be64 R255_prio_1; - __be64 R255_prio_2; - __be64 R255_prio_3; - __be64 R255_prio_4; - __be64 R255_prio_5; - __be64 R255_prio_6; - __be64 R255_prio_7; - __be64 R255_novlan; - /* Received frames with a length of 511 octets */ - __be64 R511_prio_0; - __be64 R511_prio_1; - __be64 R511_prio_2; - __be64 R511_prio_3; - __be64 R511_prio_4; - __be64 R511_prio_5; - __be64 R511_prio_6; - __be64 R511_prio_7; - __be64 R511_novlan; - /* Received frames with a length of 1023 octets */ - __be64 R1023_prio_0; - __be64 R1023_prio_1; - __be64 R1023_prio_2; - __be64 R1023_prio_3; - __be64 R1023_prio_4; - __be64 R1023_prio_5; - __be64 R1023_prio_6; - __be64 R1023_prio_7; - __be64 R1023_novlan; - /* Received frames with a length of 1518 octets */ - __be64 R1518_prio_0; - __be64 R1518_prio_1; - __be64 R1518_prio_2; - __be64 R1518_prio_3; - __be64 R1518_prio_4; - __be64 R1518_prio_5; - __be64 R1518_prio_6; - __be64 R1518_prio_7; - __be64 R1518_novlan; - /* Received frames with a length of 1522 octets */ - __be64 R1522_prio_0; - __be64 R1522_prio_1; - __be64 R1522_prio_2; - __be64 R1522_prio_3; - __be64 R1522_prio_4; - __be64 R1522_prio_5; - __be64 R1522_prio_6; - __be64 R1522_prio_7; - __be64 R1522_novlan; - /* Received frames with a length of 1548 octets */ - __be64 R1548_prio_0; - __be64 R1548_prio_1; - __be64 R1548_prio_2; - __be64 R1548_prio_3; - __be64 R1548_prio_4; - __be64 R1548_prio_5; - __be64 R1548_prio_6; - __be64 R1548_prio_7; - __be64 R1548_novlan; - /* Received frames with a length of 1548 < octets < MTU */ - __be64 R2MTU_prio_0; - __be64 R2MTU_prio_1; - __be64 R2MTU_prio_2; - __be64 R2MTU_prio_3; - __be64 R2MTU_prio_4; - __be64 R2MTU_prio_5; - __be64 R2MTU_prio_6; - __be64 R2MTU_prio_7; - __be64 R2MTU_novlan; - /* Received frames with a length of MTU< octets and good CRC */ - __be64 RGIANT_prio_0; - __be64 RGIANT_prio_1; - __be64 RGIANT_prio_2; - __be64 RGIANT_prio_3; - __be64 RGIANT_prio_4; - __be64 RGIANT_prio_5; - __be64 RGIANT_prio_6; - __be64 RGIANT_prio_7; - __be64 RGIANT_novlan; - /* Received broadcast frames with good CRC */ - __be64 RBCAST_prio_0; - __be64 RBCAST_prio_1; - __be64 RBCAST_prio_2; - __be64 RBCAST_prio_3; - __be64 RBCAST_prio_4; - __be64 RBCAST_prio_5; - __be64 RBCAST_prio_6; - __be64 RBCAST_prio_7; - __be64 RBCAST_novlan; - /* Received multicast frames with good CRC */ - __be64 MCAST_prio_0; - __be64 MCAST_prio_1; - __be64 MCAST_prio_2; - __be64 MCAST_prio_3; - __be64 MCAST_prio_4; - __be64 MCAST_prio_5; - __be64 MCAST_prio_6; - __be64 MCAST_prio_7; - __be64 MCAST_novlan; - /* Received unicast not short or GIANT frames with good CRC */ - __be64 RTOTG_prio_0; - __be64 RTOTG_prio_1; - __be64 RTOTG_prio_2; - __be64 RTOTG_prio_3; - __be64 RTOTG_prio_4; - __be64 RTOTG_prio_5; - __be64 RTOTG_prio_6; - __be64 RTOTG_prio_7; - __be64 RTOTG_novlan; - - /* Count of total octets of received frames, includes framing characters */ - __be64 RTTLOCT_prio_0; - /* Count of total octets of received frames, not including framing - characters */ - __be64 RTTLOCT_NOFRM_prio_0; - /* Count of Total number of octets received - (only for frames without errors) */ - __be64 ROCT_prio_0; - - __be64 RTTLOCT_prio_1; - __be64 RTTLOCT_NOFRM_prio_1; - __be64 ROCT_prio_1; - - __be64 RTTLOCT_prio_2; - __be64 RTTLOCT_NOFRM_prio_2; - __be64 ROCT_prio_2; - - __be64 RTTLOCT_prio_3; - __be64 RTTLOCT_NOFRM_prio_3; - __be64 ROCT_prio_3; - - __be64 RTTLOCT_prio_4; - __be64 RTTLOCT_NOFRM_prio_4; - __be64 ROCT_prio_4; - - __be64 RTTLOCT_prio_5; - __be64 RTTLOCT_NOFRM_prio_5; - __be64 ROCT_prio_5; - - __be64 RTTLOCT_prio_6; - __be64 RTTLOCT_NOFRM_prio_6; - __be64 ROCT_prio_6; - - __be64 RTTLOCT_prio_7; - __be64 RTTLOCT_NOFRM_prio_7; - __be64 ROCT_prio_7; - - __be64 RTTLOCT_novlan; - __be64 RTTLOCT_NOFRM_novlan; - __be64 ROCT_novlan; - - /* Count of Total received frames including bad frames */ - __be64 RTOT_prio_0; - /* Count of Total number of received frames with 802.1Q encapsulation */ - __be64 R1Q_prio_0; - __be64 reserved1; - - __be64 RTOT_prio_1; - __be64 R1Q_prio_1; - __be64 reserved2; - - __be64 RTOT_prio_2; - __be64 R1Q_prio_2; - __be64 reserved3; - - __be64 RTOT_prio_3; - __be64 R1Q_prio_3; - __be64 reserved4; - - __be64 RTOT_prio_4; - __be64 R1Q_prio_4; - __be64 reserved5; - - __be64 RTOT_prio_5; - __be64 R1Q_prio_5; - __be64 reserved6; - - __be64 RTOT_prio_6; - __be64 R1Q_prio_6; - __be64 reserved7; - - __be64 RTOT_prio_7; - __be64 R1Q_prio_7; - __be64 reserved8; - - __be64 RTOT_novlan; - __be64 R1Q_novlan; - __be64 reserved9; - - /* Total number of Successfully Received Control Frames */ - __be64 RCNTL; - __be64 reserved10; - __be64 reserved11; - __be64 reserved12; - /* Count of received frames with a length/type field value between 46 - (42 for VLANtagged frames) and 1500 (also 1500 for VLAN-tagged frames), - inclusive */ - __be64 RInRangeLengthErr; - /* Count of received frames with length/type field between 1501 and 1535 - decimal, inclusive */ - __be64 ROutRangeLengthErr; - /* Count of received frames that are longer than max allowed size for - 802.3 frames (1518/1522) */ - __be64 RFrmTooLong; - /* Count frames received with PCS error */ - __be64 PCS; - - /* Transmit frames with a length of 64 octets */ - __be64 T64_prio_0; - __be64 T64_prio_1; - __be64 T64_prio_2; - __be64 T64_prio_3; - __be64 T64_prio_4; - __be64 T64_prio_5; - __be64 T64_prio_6; - __be64 T64_prio_7; - __be64 T64_novlan; - __be64 T64_loopbk; - /* Transmit frames with a length of 65 to 127 octets. */ - __be64 T127_prio_0; - __be64 T127_prio_1; - __be64 T127_prio_2; - __be64 T127_prio_3; - __be64 T127_prio_4; - __be64 T127_prio_5; - __be64 T127_prio_6; - __be64 T127_prio_7; - __be64 T127_novlan; - __be64 T127_loopbk; - /* Transmit frames with a length of 128 to 255 octets */ - __be64 T255_prio_0; - __be64 T255_prio_1; - __be64 T255_prio_2; - __be64 T255_prio_3; - __be64 T255_prio_4; - __be64 T255_prio_5; - __be64 T255_prio_6; - __be64 T255_prio_7; - __be64 T255_novlan; - __be64 T255_loopbk; - /* Transmit frames with a length of 256 to 511 octets */ - __be64 T511_prio_0; - __be64 T511_prio_1; - __be64 T511_prio_2; - __be64 T511_prio_3; - __be64 T511_prio_4; - __be64 T511_prio_5; - __be64 T511_prio_6; - __be64 T511_prio_7; - __be64 T511_novlan; - __be64 T511_loopbk; - /* Transmit frames with a length of 512 to 1023 octets */ - __be64 T1023_prio_0; - __be64 T1023_prio_1; - __be64 T1023_prio_2; - __be64 T1023_prio_3; - __be64 T1023_prio_4; - __be64 T1023_prio_5; - __be64 T1023_prio_6; - __be64 T1023_prio_7; - __be64 T1023_novlan; - __be64 T1023_loopbk; - /* Transmit frames with a length of 1024 to 1518 octets */ - __be64 T1518_prio_0; - __be64 T1518_prio_1; - __be64 T1518_prio_2; - __be64 T1518_prio_3; - __be64 T1518_prio_4; - __be64 T1518_prio_5; - __be64 T1518_prio_6; - __be64 T1518_prio_7; - __be64 T1518_novlan; - __be64 T1518_loopbk; - /* Counts transmit frames with a length of 1519 to 1522 bytes */ - __be64 T1522_prio_0; - __be64 T1522_prio_1; - __be64 T1522_prio_2; - __be64 T1522_prio_3; - __be64 T1522_prio_4; - __be64 T1522_prio_5; - __be64 T1522_prio_6; - __be64 T1522_prio_7; - __be64 T1522_novlan; - __be64 T1522_loopbk; - /* Transmit frames with a length of 1523 to 1548 octets */ - __be64 T1548_prio_0; - __be64 T1548_prio_1; - __be64 T1548_prio_2; - __be64 T1548_prio_3; - __be64 T1548_prio_4; - __be64 T1548_prio_5; - __be64 T1548_prio_6; - __be64 T1548_prio_7; - __be64 T1548_novlan; - __be64 T1548_loopbk; - /* Counts transmit frames with a length of 1549 to MTU bytes */ - __be64 T2MTU_prio_0; - __be64 T2MTU_prio_1; - __be64 T2MTU_prio_2; - __be64 T2MTU_prio_3; - __be64 T2MTU_prio_4; - __be64 T2MTU_prio_5; - __be64 T2MTU_prio_6; - __be64 T2MTU_prio_7; - __be64 T2MTU_novlan; - __be64 T2MTU_loopbk; - /* Transmit frames with a length greater than MTU octets and a good CRC. */ - __be64 TGIANT_prio_0; - __be64 TGIANT_prio_1; - __be64 TGIANT_prio_2; - __be64 TGIANT_prio_3; - __be64 TGIANT_prio_4; - __be64 TGIANT_prio_5; - __be64 TGIANT_prio_6; - __be64 TGIANT_prio_7; - __be64 TGIANT_novlan; - __be64 TGIANT_loopbk; - /* Transmit broadcast frames with a good CRC */ - __be64 TBCAST_prio_0; - __be64 TBCAST_prio_1; - __be64 TBCAST_prio_2; - __be64 TBCAST_prio_3; - __be64 TBCAST_prio_4; - __be64 TBCAST_prio_5; - __be64 TBCAST_prio_6; - __be64 TBCAST_prio_7; - __be64 TBCAST_novlan; - __be64 TBCAST_loopbk; - /* Transmit multicast frames with a good CRC */ - __be64 TMCAST_prio_0; - __be64 TMCAST_prio_1; - __be64 TMCAST_prio_2; - __be64 TMCAST_prio_3; - __be64 TMCAST_prio_4; - __be64 TMCAST_prio_5; - __be64 TMCAST_prio_6; - __be64 TMCAST_prio_7; - __be64 TMCAST_novlan; - __be64 TMCAST_loopbk; - /* Transmit good frames that are neither broadcast nor multicast */ - __be64 TTOTG_prio_0; - __be64 TTOTG_prio_1; - __be64 TTOTG_prio_2; - __be64 TTOTG_prio_3; - __be64 TTOTG_prio_4; - __be64 TTOTG_prio_5; - __be64 TTOTG_prio_6; - __be64 TTOTG_prio_7; - __be64 TTOTG_novlan; - __be64 TTOTG_loopbk; - - /* total octets of transmitted frames, including framing characters */ - __be64 TTTLOCT_prio_0; - /* total octets of transmitted frames, not including framing characters */ - __be64 TTTLOCT_NOFRM_prio_0; - /* ifOutOctets */ - __be64 TOCT_prio_0; - - __be64 TTTLOCT_prio_1; - __be64 TTTLOCT_NOFRM_prio_1; - __be64 TOCT_prio_1; - - __be64 TTTLOCT_prio_2; - __be64 TTTLOCT_NOFRM_prio_2; - __be64 TOCT_prio_2; - - __be64 TTTLOCT_prio_3; - __be64 TTTLOCT_NOFRM_prio_3; - __be64 TOCT_prio_3; - - __be64 TTTLOCT_prio_4; - __be64 TTTLOCT_NOFRM_prio_4; - __be64 TOCT_prio_4; - - __be64 TTTLOCT_prio_5; - __be64 TTTLOCT_NOFRM_prio_5; - __be64 TOCT_prio_5; - - __be64 TTTLOCT_prio_6; - __be64 TTTLOCT_NOFRM_prio_6; - __be64 TOCT_prio_6; - - __be64 TTTLOCT_prio_7; - __be64 TTTLOCT_NOFRM_prio_7; - __be64 TOCT_prio_7; - - __be64 TTTLOCT_novlan; - __be64 TTTLOCT_NOFRM_novlan; - __be64 TOCT_novlan; - - __be64 TTTLOCT_loopbk; - __be64 TTTLOCT_NOFRM_loopbk; - __be64 TOCT_loopbk; - - /* Total frames transmitted with a good CRC that are not aborted */ - __be64 TTOT_prio_0; - /* Total number of frames transmitted with 802.1Q encapsulation */ - __be64 T1Q_prio_0; - __be64 reserved13; - - __be64 TTOT_prio_1; - __be64 T1Q_prio_1; - __be64 reserved14; - - __be64 TTOT_prio_2; - __be64 T1Q_prio_2; - __be64 reserved15; - - __be64 TTOT_prio_3; - __be64 T1Q_prio_3; - __be64 reserved16; - - __be64 TTOT_prio_4; - __be64 T1Q_prio_4; - __be64 reserved17; - - __be64 TTOT_prio_5; - __be64 T1Q_prio_5; - __be64 reserved18; - - __be64 TTOT_prio_6; - __be64 T1Q_prio_6; - __be64 reserved19; - - __be64 TTOT_prio_7; - __be64 T1Q_prio_7; - __be64 reserved20; - - __be64 TTOT_novlan; - __be64 T1Q_novlan; - __be64 reserved21; - - __be64 TTOT_loopbk; - __be64 T1Q_loopbk; - __be64 reserved22; - - /* Received frames with a length greater than MTU octets and a bad CRC */ - __be32 RJBBR; - /* Received frames with a bad CRC that are not runts, jabbers, - or alignment errors */ - __be32 RCRC; - /* Received frames with SFD with a length of less than 64 octets and a - bad CRC */ - __be32 RRUNT; - /* Received frames with a length less than 64 octets and a good CRC */ - __be32 RSHORT; - /* Total Number of Received Packets Dropped */ - __be32 RDROP; - /* Drop due to overflow */ - __be32 RdropOvflw; - /* Drop due to overflow */ - __be32 RdropLength; - /* Total of good frames. Does not include frames received with - frame-too-long, FCS, or length errors */ - __be32 RTOTFRMS; - /* Total dropped Xmited packets */ - __be32 TDROP; -}; - - -#endif diff --git a/sys/ofed/drivers/net/mlx4/en_resources.c b/sys/ofed/drivers/net/mlx4/en_resources.c deleted file mode 100644 index 669ecbd11843..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_resources.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/mlx4/qp.h> - -#include "mlx4_en.h" - - -void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, - int user_prio, struct mlx4_qp_context *context) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - - memset(context, 0, sizeof *context); - context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET); - context->pd = cpu_to_be32(mdev->priv_pdn); - context->mtu_msgmax = 0xff; - if (!is_tx && !rss) - context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - if (is_tx) - context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - else - context->sq_size_stride = ilog2(TXBB_SIZE) - 4; - context->usr_page = cpu_to_be32(mdev->priv_uar.index); - context->local_qpn = cpu_to_be32(qpn); - context->pri_path.ackto = 1 & 0x07; - context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; - if (user_prio >= 0) { - context->pri_path.sched_queue |= user_prio << 3; - context->pri_path.feup = 1 << 6; - } - context->pri_path.counter_index = (u8)(priv->counter_index); - if (!rss && - (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && - context->pri_path.counter_index != 0xFF) { - /* disable multicast loopback to qp with same counter */ - context->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; - context->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - } - - context->cqn_send = cpu_to_be32(cqn); - context->cqn_recv = cpu_to_be32(cqn); - context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); - if (!(dev->if_capabilities & IFCAP_VLAN_HWCSUM)) - context->param3 |= cpu_to_be32(1 << 30); -} - - -int mlx4_en_map_buffer(struct mlx4_buf *buf) -{ - struct page **pages; - int i; - - // if nbufs == 1 - there is no need to vmap - // if buf->direct.buf is not NULL it means that vmap was already done by mlx4_alloc_buff - if (buf->direct.buf != NULL || buf->nbufs == 1) - return 0; - - pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); - if (!pages) - return -ENOMEM; - - for (i = 0; i < buf->nbufs; ++i) - pages[i] = virt_to_page(buf->page_list[i].buf); - - buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); - kfree(pages); - if (!buf->direct.buf) - return -ENOMEM; - - return 0; -} - -void mlx4_en_unmap_buffer(struct mlx4_buf *buf) -{ - if (BITS_PER_LONG == 64 || buf->nbufs == 1) - return; - - vunmap(buf->direct.buf); -} - -void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event) -{ - return; -} - diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c deleted file mode 100644 index 2711b22b8667..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_rx.c +++ /dev/null @@ -1,922 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ -#include "opt_inet.h" -#include <linux/mlx4/cq.h> -#include <linux/slab.h> -#include <linux/mlx4/qp.h> -#include <linux/if_ether.h> -#include <linux/if_vlan.h> -#include <linux/vmalloc.h> -#include <linux/mlx4/driver.h> -#ifdef CONFIG_NET_RX_BUSY_POLL -#include <net/busy_poll.h> -#endif - -#include "mlx4_en.h" - - -static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring, - int index) -{ - struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (ring->stride * index)); - int possible_frags; - int i; - - /* Set size and memtype fields */ - rx_desc->data[0].byte_count = cpu_to_be32(priv->rx_mb_size - MLX4_NET_IP_ALIGN); - rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key); - - /* - * If the number of used fragments does not fill up the ring - * stride, remaining (unused) fragments must be padded with - * null address/size and a special memory key: - */ - possible_frags = (ring->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE; - for (i = 1; i < possible_frags; i++) { - rx_desc->data[i].byte_count = 0; - rx_desc->data[i].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD); - rx_desc->data[i].addr = 0; - } -} - -static int -mlx4_en_alloc_buf(struct mlx4_en_rx_ring *ring, - __be64 *pdma, struct mlx4_en_rx_mbuf *mb_list) -{ - bus_dma_segment_t segs[1]; - bus_dmamap_t map; - struct mbuf *mb; - int nsegs; - int err; - - /* try to allocate a new spare mbuf */ - if (unlikely(ring->spare.mbuf == NULL)) { - mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size); - if (unlikely(mb == NULL)) - return (-ENOMEM); - /* setup correct length */ - mb->m_pkthdr.len = mb->m_len = ring->rx_mb_size; - - /* make sure IP header gets aligned */ - m_adj(mb, MLX4_NET_IP_ALIGN); - - /* load spare mbuf into BUSDMA */ - err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, ring->spare.dma_map, - mb, segs, &nsegs, BUS_DMA_NOWAIT); - if (unlikely(err != 0)) { - m_freem(mb); - return (err); - } - - /* store spare info */ - ring->spare.mbuf = mb; - ring->spare.paddr_be = cpu_to_be64(segs[0].ds_addr); - - bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map, - BUS_DMASYNC_PREREAD); - } - - /* synchronize and unload the current mbuf, if any */ - if (likely(mb_list->mbuf != NULL)) { - bus_dmamap_sync(ring->dma_tag, mb_list->dma_map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, mb_list->dma_map); - } - - mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size); - if (unlikely(mb == NULL)) - goto use_spare; - - /* setup correct length */ - mb->m_pkthdr.len = mb->m_len = ring->rx_mb_size; - - /* make sure IP header gets aligned */ - m_adj(mb, MLX4_NET_IP_ALIGN); - - err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, mb_list->dma_map, - mb, segs, &nsegs, BUS_DMA_NOWAIT); - if (unlikely(err != 0)) { - m_freem(mb); - goto use_spare; - } - - *pdma = cpu_to_be64(segs[0].ds_addr); - mb_list->mbuf = mb; - - bus_dmamap_sync(ring->dma_tag, mb_list->dma_map, BUS_DMASYNC_PREREAD); - return (0); - -use_spare: - /* swap DMA maps */ - map = mb_list->dma_map; - mb_list->dma_map = ring->spare.dma_map; - ring->spare.dma_map = map; - - /* swap MBUFs */ - mb_list->mbuf = ring->spare.mbuf; - ring->spare.mbuf = NULL; - - /* store physical address */ - *pdma = ring->spare.paddr_be; - return (0); -} - -static void -mlx4_en_free_buf(struct mlx4_en_rx_ring *ring, struct mlx4_en_rx_mbuf *mb_list) -{ - bus_dmamap_t map = mb_list->dma_map; - bus_dmamap_sync(ring->dma_tag, map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, map); - m_freem(mb_list->mbuf); - mb_list->mbuf = NULL; /* safety clearing */ -} - -static int -mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring, int index) -{ - struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (index * ring->stride)); - struct mlx4_en_rx_mbuf *mb_list = ring->mbuf + index; - - mb_list->mbuf = NULL; - - if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list)) { - priv->port_stats.rx_alloc_failed++; - return (-ENOMEM); - } - return (0); -} - -static inline void -mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) -{ - *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); -} - -static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) -{ - struct mlx4_en_rx_ring *ring; - int ring_ind; - int buf_ind; - int new_size; - int err; - - for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - err = mlx4_en_prepare_rx_desc(priv, ring, - ring->actual_size); - if (err) { - if (ring->actual_size == 0) { - en_err(priv, "Failed to allocate " - "enough rx buffers\n"); - return -ENOMEM; - } else { - new_size = - rounddown_pow_of_two(ring->actual_size); - en_warn(priv, "Only %d buffers allocated " - "reducing ring size to %d\n", - ring->actual_size, new_size); - goto reduce_rings; - } - } - ring->actual_size++; - ring->prod++; - } - } - return 0; - -reduce_rings: - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - while (ring->actual_size > new_size) { - ring->actual_size--; - ring->prod--; - mlx4_en_free_buf(ring, - ring->mbuf + ring->actual_size); - } - } - - return 0; -} - -static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) -{ - int index; - - en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", - ring->cons, ring->prod); - - /* Unmap and free Rx buffers */ - BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); - while (ring->cons != ring->prod) { - index = ring->cons & ring->size_mask; - en_dbg(DRV, priv, "Processing descriptor:%d\n", index); - mlx4_en_free_buf(ring, ring->mbuf + index); - ++ring->cons; - } -} - -void mlx4_en_calc_rx_buf(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int eff_mtu = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN + - MLX4_NET_IP_ALIGN; - - if (eff_mtu > MJUM16BYTES) { - en_err(priv, "MTU(%d) is too big\n", dev->if_mtu); - eff_mtu = MJUM16BYTES; - } else if (eff_mtu > MJUM9BYTES) { - eff_mtu = MJUM16BYTES; - } else if (eff_mtu > MJUMPAGESIZE) { - eff_mtu = MJUM9BYTES; - } else if (eff_mtu > MCLBYTES) { - eff_mtu = MJUMPAGESIZE; - } else { - eff_mtu = MCLBYTES; - } - - priv->rx_mb_size = eff_mtu; - - en_dbg(DRV, priv, "Effective RX MTU: %d bytes\n", eff_mtu); -} - -int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, int node) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rx_ring *ring; - int err; - int tmp; - uint32_t x; - - ring = kzalloc(sizeof(struct mlx4_en_rx_ring), GFP_KERNEL); - if (!ring) { - en_err(priv, "Failed to allocate RX ring structure\n"); - return -ENOMEM; - } - - /* Create DMA descriptor TAG */ - if ((err = -bus_dma_tag_create( - bus_get_dma_tag(mdev->pdev->dev.bsddev), - 1, /* any alignment */ - 0, /* no boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 1, /* nsegments */ - MJUM16BYTES, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockfuncarg */ - &ring->dma_tag))) { - en_err(priv, "Failed to create DMA tag\n"); - goto err_ring; - } - - ring->prod = 0; - ring->cons = 0; - ring->size = size; - ring->size_mask = size - 1; - ring->stride = roundup_pow_of_two( - sizeof(struct mlx4_en_rx_desc) + DS_SIZE); - ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride + TXBB_SIZE; - - tmp = size * sizeof(struct mlx4_en_rx_mbuf); - - ring->mbuf = kzalloc(tmp, GFP_KERNEL); - if (ring->mbuf == NULL) { - err = -ENOMEM; - goto err_dma_tag; - } - - err = -bus_dmamap_create(ring->dma_tag, 0, &ring->spare.dma_map); - if (err != 0) - goto err_info; - - for (x = 0; x != size; x++) { - err = -bus_dmamap_create(ring->dma_tag, 0, - &ring->mbuf[x].dma_map); - if (err != 0) { - while (x--) - bus_dmamap_destroy(ring->dma_tag, - ring->mbuf[x].dma_map); - goto err_info; - } - } - en_dbg(DRV, priv, "Allocated MBUF ring at addr:%p size:%d\n", - ring->mbuf, tmp); - - err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, - ring->buf_size, 2 * PAGE_SIZE); - if (err) - goto err_dma_map; - - err = mlx4_en_map_buffer(&ring->wqres.buf); - if (err) { - en_err(priv, "Failed to map RX buffer\n"); - goto err_hwq; - } - ring->buf = ring->wqres.buf.direct.buf; - *pring = ring; - return 0; - -err_hwq: - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); -err_dma_map: - for (x = 0; x != size; x++) { - bus_dmamap_destroy(ring->dma_tag, - ring->mbuf[x].dma_map); - } - bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map); -err_info: - vfree(ring->mbuf); -err_dma_tag: - bus_dma_tag_destroy(ring->dma_tag); -err_ring: - kfree(ring); - return (err); -} - -int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) -{ - struct mlx4_en_rx_ring *ring; - int i; - int ring_ind; - int err; - int stride = roundup_pow_of_two( - sizeof(struct mlx4_en_rx_desc) + DS_SIZE); - - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - ring->prod = 0; - ring->cons = 0; - ring->actual_size = 0; - ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn; - ring->rx_mb_size = priv->rx_mb_size; - - ring->stride = stride; - if (ring->stride <= TXBB_SIZE) - ring->buf += TXBB_SIZE; - - ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride; - - memset(ring->buf, 0, ring->buf_size); - mlx4_en_update_rx_prod_db(ring); - - /* Initialize all descriptors */ - for (i = 0; i < ring->size; i++) - mlx4_en_init_rx_desc(priv, ring, i); - -#ifdef INET - /* Configure lro mngr */ - if (priv->dev->if_capenable & IFCAP_LRO) { - if (tcp_lro_init(&ring->lro)) - priv->dev->if_capenable &= ~IFCAP_LRO; - else - ring->lro.ifp = priv->dev; - } -#endif - } - - - err = mlx4_en_fill_rx_buffers(priv); - if (err) - goto err_buffers; - - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - ring->size_mask = ring->actual_size - 1; - mlx4_en_update_rx_prod_db(ring); - } - - return 0; - -err_buffers: - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) - mlx4_en_free_rx_buf(priv, priv->rx_ring[ring_ind]); - - ring_ind = priv->rx_ring_num - 1; - - while (ring_ind >= 0) { - ring = priv->rx_ring[ring_ind]; - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; - ring_ind--; - } - - return err; -} - - -void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, u16 stride) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rx_ring *ring = *pring; - uint32_t x; - - mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, size * stride + TXBB_SIZE); - for (x = 0; x != size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->mbuf[x].dma_map); - /* free spare mbuf, if any */ - if (ring->spare.mbuf != NULL) { - bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, ring->spare.dma_map); - m_freem(ring->spare.mbuf); - } - bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map); - vfree(ring->mbuf); - bus_dma_tag_destroy(ring->dma_tag); - kfree(ring); - *pring = NULL; -#ifdef CONFIG_RFS_ACCEL - mlx4_en_cleanup_filters(priv, ring); -#endif -} - -void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) -{ -#ifdef INET - tcp_lro_free(&ring->lro); -#endif - mlx4_en_free_rx_buf(priv, ring); - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; -} - - -static void validate_loopback(struct mlx4_en_priv *priv, struct mbuf *mb) -{ - int i; - int offset = ETHER_HDR_LEN; - - for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) { - if (*(mb->m_data + offset) != (unsigned char) (i & 0xff)) - goto out_loopback; - } - /* Loopback found */ - priv->loopback_ok = 1; - -out_loopback: - m_freem(mb); -} - - -static inline int invalid_cqe(struct mlx4_en_priv *priv, - struct mlx4_cqe *cqe) -{ - /* Drop packet on bad receive or bad checksum */ - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == - MLX4_CQE_OPCODE_ERROR)) { - en_err(priv, "CQE completed in error - vendor syndrom:%d syndrom:%d\n", - ((struct mlx4_err_cqe *)cqe)->vendor_err_syndrome, - ((struct mlx4_err_cqe *)cqe)->syndrome); - return 1; - } - if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { - en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); - return 1; - } - - return 0; -} - -static struct mbuf * -mlx4_en_rx_mb(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, - struct mlx4_en_rx_desc *rx_desc, struct mlx4_en_rx_mbuf *mb_list, - int length) -{ - struct mbuf *mb; - - /* get mbuf */ - mb = mb_list->mbuf; - - /* collect used fragment while atomically replacing it */ - if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list)) - return (NULL); - - /* range check hardware computed value */ - if (unlikely(length > mb->m_len)) - length = mb->m_len; - - /* update total packet length in packet header */ - mb->m_len = mb->m_pkthdr.len = length; - return (mb); -} - -/* For cpu arch with cache line of 64B the performance is better when cqe size==64B - * To enlarge cqe size from 32B to 64B --> 32B of garbage (i.e. 0xccccccc) - * was added in the beginning of each cqe (the real data is in the corresponding 32B). - * The following calc ensures that when factor==1, it means we are aligned to 64B - * and we get the real cqe data*/ -#define CQE_FACTOR_INDEX(index, factor) ((index << factor) + factor) -int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_cqe *cqe; - struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring]; - struct mlx4_en_rx_mbuf *mb_list; - struct mlx4_en_rx_desc *rx_desc; - struct mbuf *mb; - struct mlx4_cq *mcq = &cq->mcq; - struct mlx4_cqe *buf = cq->buf; - int index; - unsigned int length; - int polled = 0; - u32 cons_index = mcq->cons_index; - u32 size_mask = ring->size_mask; - int size = cq->size; - int factor = priv->cqe_factor; - - if (!priv->port_up) - return 0; - - /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx - * descriptor offset can be deducted from the CQE index instead of - * reading 'cqe->index' */ - index = cons_index & size_mask; - cqe = &buf[CQE_FACTOR_INDEX(index, factor)]; - - /* Process all completed CQEs */ - while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, - cons_index & size)) { - mb_list = ring->mbuf + index; - rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (index << ring->log_stride)); - - /* - * make sure we read the CQE after we read the ownership bit - */ - rmb(); - - if (invalid_cqe(priv, cqe)) { - goto next; - } - /* - * Packet is OK - process it. - */ - length = be32_to_cpu(cqe->byte_cnt); - length -= ring->fcs_del; - - mb = mlx4_en_rx_mb(priv, ring, rx_desc, mb_list, length); - if (unlikely(!mb)) { - ring->errors++; - goto next; - } - - ring->bytes += length; - ring->packets++; - - if (unlikely(priv->validate_loopback)) { - validate_loopback(priv, mb); - goto next; - } - - /* forward Toeplitz compatible hash value */ - mb->m_pkthdr.flowid = be32_to_cpu(cqe->immed_rss_invalid); - M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH); - mb->m_pkthdr.rcvif = dev; - if (be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) { - mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->sl_vid); - mb->m_flags |= M_VLANTAG; - } - if (likely(dev->if_capenable & - (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) && - (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && - (cqe->checksum == cpu_to_be16(0xffff))) { - priv->port_stats.rx_chksum_good++; - mb->m_pkthdr.csum_flags = - CSUM_IP_CHECKED | CSUM_IP_VALID | - CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - mb->m_pkthdr.csum_data = htons(0xffff); - /* This packet is eligible for LRO if it is: - * - DIX Ethernet (type interpretation) - * - TCP/IP (v4) - * - without IP options - * - not an IP fragment - */ -#ifdef INET - if (mlx4_en_can_lro(cqe->status) && - (dev->if_capenable & IFCAP_LRO)) { - if (ring->lro.lro_cnt != 0 && - tcp_lro_rx(&ring->lro, mb, 0) == 0) - goto next; - } - -#endif - /* LRO not possible, complete processing here */ - INC_PERF_COUNTER(priv->pstats.lro_misses); - } else { - mb->m_pkthdr.csum_flags = 0; - priv->port_stats.rx_chksum_none++; - } - - /* Push it up the stack */ - dev->if_input(dev, mb); - -next: - ++cons_index; - index = cons_index & size_mask; - cqe = &buf[CQE_FACTOR_INDEX(index, factor)]; - if (++polled == budget) - goto out; - } - /* Flush all pending IP reassembly sessions */ -out: -#ifdef INET - tcp_lro_flush_all(&ring->lro); -#endif - AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); - mcq->cons_index = cons_index; - mlx4_cq_set_ci(mcq); - wmb(); /* ensure HW sees CQ consumer before we post new buffers */ - ring->cons = mcq->cons_index; - ring->prod += polled; /* Polled descriptors were realocated in place */ - mlx4_en_update_rx_prod_db(ring); - return polled; - -} - -/* Rx CQ polling - called by NAPI */ -static int mlx4_en_poll_rx_cq(struct mlx4_en_cq *cq, int budget) -{ - struct net_device *dev = cq->dev; - int done; - - done = mlx4_en_process_rx_cq(dev, cq, budget); - cq->tot_rx += done; - - return done; - -} -void mlx4_en_rx_irq(struct mlx4_cq *mcq) -{ - struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - int done; - - // Shoot one within the irq context - // Because there is no NAPI in freeBSD - done = mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET); - if (priv->port_up && (done == MLX4_EN_RX_BUDGET) ) { - cq->curr_poll_rx_cpu_id = curcpu; - taskqueue_enqueue(cq->tq, &cq->cq_task); - } - else { - mlx4_en_arm_cq(priv, cq); - } -} - -void mlx4_en_rx_que(void *context, int pending) -{ - struct mlx4_en_cq *cq; - struct thread *td; - - cq = context; - td = curthread; - - thread_lock(td); - sched_bind(td, cq->curr_poll_rx_cpu_id); - thread_unlock(td); - - while (mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET) - == MLX4_EN_RX_BUDGET); - mlx4_en_arm_cq(cq->dev->if_softc, cq); -} - - -/* RSS related functions */ - -static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, - struct mlx4_en_rx_ring *ring, - enum mlx4_qp_state *state, - struct mlx4_qp *qp) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_qp_context *context; - int err = 0; - - context = kmalloc(sizeof *context , GFP_KERNEL); - if (!context) { - en_err(priv, "Failed to allocate qp context\n"); - return -ENOMEM; - } - - err = mlx4_qp_alloc(mdev->dev, qpn, qp); - if (err) { - en_err(priv, "Failed to allocate qp #%x\n", qpn); - goto out; - } - qp->event = mlx4_en_sqp_event; - - memset(context, 0, sizeof *context); - mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, - qpn, ring->cqn, -1, context); - context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); - - /* Cancel FCS removal if FW allows */ - if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) { - context->param3 |= cpu_to_be32(1 << 29); - ring->fcs_del = ETH_FCS_LEN; - } else - ring->fcs_del = 0; - - err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); - if (err) { - mlx4_qp_remove(mdev->dev, qp); - mlx4_qp_free(mdev->dev, qp); - } - mlx4_en_update_rx_prod_db(ring); -out: - kfree(context); - return err; -} - -int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv) -{ - int err; - u32 qpn; - - err = mlx4_qp_reserve_range(priv->mdev->dev, 1, 1, &qpn, 0); - if (err) { - en_err(priv, "Failed reserving drop qpn\n"); - return err; - } - err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp); - if (err) { - en_err(priv, "Failed allocating drop qp\n"); - mlx4_qp_release_range(priv->mdev->dev, qpn, 1); - return err; - } - - return 0; -} - -void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv) -{ - u32 qpn; - - qpn = priv->drop_qp.qpn; - mlx4_qp_remove(priv->mdev->dev, &priv->drop_qp); - mlx4_qp_free(priv->mdev->dev, &priv->drop_qp); - mlx4_qp_release_range(priv->mdev->dev, qpn, 1); -} - -/* Allocate rx qp's and configure them according to rss map */ -int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rss_map *rss_map = &priv->rss_map; - struct mlx4_qp_context context; - struct mlx4_rss_context *rss_context; - int rss_rings; - void *ptr; - u8 rss_mask = (MLX4_RSS_IPV4 | MLX4_RSS_TCP_IPV4 | MLX4_RSS_IPV6 | - MLX4_RSS_TCP_IPV6); - int i; - int err = 0; - int good_qps = 0; - static const u32 rsskey[10] = { 0xD181C62C, 0xF7F4DB5B, 0x1983A2FC, - 0x943E1ADB, 0xD9389E6B, 0xD1039C2C, 0xA74499AD, - 0x593D56D9, 0xF3253C06, 0x2ADC1FFC}; - - en_dbg(DRV, priv, "Configuring rss steering\n"); - err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, - priv->rx_ring_num, - &rss_map->base_qpn, 0); - if (err) { - en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); - return err; - } - - for (i = 0; i < priv->rx_ring_num; i++) { - priv->rx_ring[i]->qpn = rss_map->base_qpn + i; - err = mlx4_en_config_rss_qp(priv, priv->rx_ring[i]->qpn, - priv->rx_ring[i], - &rss_map->state[i], - &rss_map->qps[i]); - if (err) - goto rss_err; - - ++good_qps; - } - - /* Configure RSS indirection qp */ - err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); - if (err) { - en_err(priv, "Failed to allocate RSS indirection QP\n"); - goto rss_err; - } - rss_map->indir_qp.event = mlx4_en_sqp_event; - mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, - priv->rx_ring[0]->cqn, -1, &context); - - if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num) - rss_rings = priv->rx_ring_num; - else - rss_rings = priv->prof->rss_rings; - - ptr = ((u8 *)&context) + offsetof(struct mlx4_qp_context, pri_path) + - MLX4_RSS_OFFSET_IN_QPC_PRI_PATH; - rss_context = ptr; - rss_context->base_qpn = cpu_to_be32(ilog2(rss_rings) << 24 | - (rss_map->base_qpn)); - rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); - if (priv->mdev->profile.udp_rss) { - rss_mask |= MLX4_RSS_UDP_IPV4 | MLX4_RSS_UDP_IPV6; - rss_context->base_qpn_udp = rss_context->default_qpn; - } - rss_context->flags = rss_mask; - rss_context->hash_fn = MLX4_RSS_HASH_TOP; - for (i = 0; i < 10; i++) - rss_context->rss_key[i] = cpu_to_be32(rsskey[i]); - - err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, - &rss_map->indir_qp, &rss_map->indir_state); - if (err) - goto indir_err; - - return 0; - -indir_err: - mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); -rss_err: - for (i = 0; i < good_qps; i++) { - mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); - mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); - mlx4_qp_free(mdev->dev, &rss_map->qps[i]); - } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); - return err; -} - -void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rss_map *rss_map = &priv->rss_map; - int i; - - mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); - - for (i = 0; i < priv->rx_ring_num; i++) { - mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); - mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); - mlx4_qp_free(mdev->dev, &rss_map->qps[i]); - } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); -} - diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c deleted file mode 100644 index 9090c51679dd..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_tx.c +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/page.h> -#include <linux/mlx4/cq.h> -#include <linux/slab.h> -#include <linux/mlx4/qp.h> -#include <linux/if_vlan.h> -#include <linux/vmalloc.h> -#include <linux/moduleparam.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/if_ether.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/tcp.h> -#include <netinet/tcp_lro.h> -#include <netinet/udp.h> - -#include "mlx4_en.h" - -enum { - MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ - MAX_BF = 256, - MIN_PKT_LEN = 17, -}; - -static int inline_thold __read_mostly = MAX_INLINE; - -module_param_named(inline_thold, inline_thold, uint, 0444); -MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); - -int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring, u32 size, - u16 stride, int node, int queue_idx) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_tx_ring *ring; - uint32_t x; - int tmp; - int err; - - ring = kzalloc_node(sizeof(struct mlx4_en_tx_ring), GFP_KERNEL, node); - if (!ring) { - ring = kzalloc(sizeof(struct mlx4_en_tx_ring), GFP_KERNEL); - if (!ring) { - en_err(priv, "Failed allocating TX ring\n"); - return -ENOMEM; - } - } - - /* Create DMA descriptor TAG */ - if ((err = -bus_dma_tag_create( - bus_get_dma_tag(mdev->pdev->dev.bsddev), - 1, /* any alignment */ - 0, /* no boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MLX4_EN_TX_MAX_PAYLOAD_SIZE, /* maxsize */ - MLX4_EN_TX_MAX_MBUF_FRAGS, /* nsegments */ - MLX4_EN_TX_MAX_MBUF_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockfuncarg */ - &ring->dma_tag))) - goto done; - - ring->size = size; - ring->size_mask = size - 1; - ring->stride = stride; - ring->inline_thold = MAX(MIN_PKT_LEN, MIN(inline_thold, MAX_INLINE)); - mtx_init(&ring->tx_lock.m, "mlx4 tx", NULL, MTX_DEF); - mtx_init(&ring->comp_lock.m, "mlx4 comp", NULL, MTX_DEF); - - /* Allocate the buf ring */ - ring->br = buf_ring_alloc(MLX4_EN_DEF_TX_QUEUE_SIZE, M_DEVBUF, - M_WAITOK, &ring->tx_lock.m); - if (ring->br == NULL) { - en_err(priv, "Failed allocating tx_info ring\n"); - err = -ENOMEM; - goto err_free_dma_tag; - } - - tmp = size * sizeof(struct mlx4_en_tx_info); - ring->tx_info = kzalloc_node(tmp, GFP_KERNEL, node); - if (!ring->tx_info) { - ring->tx_info = kzalloc(tmp, GFP_KERNEL); - if (!ring->tx_info) { - err = -ENOMEM; - goto err_ring; - } - } - - /* Create DMA descriptor MAPs */ - for (x = 0; x != size; x++) { - err = -bus_dmamap_create(ring->dma_tag, 0, - &ring->tx_info[x].dma_map); - if (err != 0) { - while (x--) { - bus_dmamap_destroy(ring->dma_tag, - ring->tx_info[x].dma_map); - } - goto err_info; - } - } - - en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", - ring->tx_info, tmp); - - ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE); - - /* Allocate HW buffers on provided NUMA node */ - err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, - 2 * PAGE_SIZE); - if (err) { - en_err(priv, "Failed allocating hwq resources\n"); - goto err_dma_map; - } - - err = mlx4_en_map_buffer(&ring->wqres.buf); - if (err) { - en_err(priv, "Failed to map TX buffer\n"); - goto err_hwq_res; - } - - ring->buf = ring->wqres.buf.direct.buf; - - en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " - "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, - ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); - - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn, - MLX4_RESERVE_BF_QP); - if (err) { - en_err(priv, "failed reserving qp for TX ring\n"); - goto err_map; - } - - err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); - if (err) { - en_err(priv, "Failed allocating qp %d\n", ring->qpn); - goto err_reserve; - } - ring->qp.event = mlx4_en_sqp_event; - - err = mlx4_bf_alloc(mdev->dev, &ring->bf, node); - if (err) { - en_dbg(DRV, priv, "working without blueflame (%d)", err); - ring->bf.uar = &mdev->priv_uar; - ring->bf.uar->map = mdev->uar_map; - ring->bf_enabled = false; - } else - ring->bf_enabled = true; - ring->queue_index = queue_idx; - if (queue_idx < priv->num_tx_rings_p_up ) - CPU_SET(queue_idx, &ring->affinity_mask); - - *pring = ring; - return 0; - -err_reserve: - mlx4_qp_release_range(mdev->dev, ring->qpn, 1); -err_map: - mlx4_en_unmap_buffer(&ring->wqres.buf); -err_hwq_res: - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); -err_dma_map: - for (x = 0; x != size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map); -err_info: - vfree(ring->tx_info); -err_ring: - buf_ring_free(ring->br, M_DEVBUF); -err_free_dma_tag: - bus_dma_tag_destroy(ring->dma_tag); -done: - kfree(ring); - return err; -} - -void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_tx_ring *ring = *pring; - uint32_t x; - en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); - - buf_ring_free(ring->br, M_DEVBUF); - if (ring->bf_enabled) - mlx4_bf_free(mdev->dev, &ring->bf); - mlx4_qp_remove(mdev->dev, &ring->qp); - mlx4_qp_free(mdev->dev, &ring->qp); - mlx4_qp_release_range(priv->mdev->dev, ring->qpn, 1); - mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); - for (x = 0; x != ring->size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map); - vfree(ring->tx_info); - mtx_destroy(&ring->tx_lock.m); - mtx_destroy(&ring->comp_lock.m); - bus_dma_tag_destroy(ring->dma_tag); - kfree(ring); - *pring = NULL; -} - -int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, - int cq, int user_prio) -{ - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - ring->cqn = cq; - ring->prod = 0; - ring->cons = 0xffffffff; - ring->last_nr_txbb = 1; - ring->poll_cnt = 0; - ring->blocked = 0; - memset(ring->buf, 0, ring->buf_size); - - ring->qp_state = MLX4_QP_STATE_RST; - ring->doorbell_qpn = ring->qp.qpn << 8; - - mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, - ring->cqn, user_prio, &ring->context); - if (ring->bf_enabled) - ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); - - err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, - &ring->qp, &ring->qp_state); - return err; -} - -void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring) -{ - struct mlx4_en_dev *mdev = priv->mdev; - - mlx4_qp_modify(mdev->dev, NULL, ring->qp_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp); -} - -static volatile struct mlx4_wqe_data_seg * -mlx4_en_store_inline_lso_data(volatile struct mlx4_wqe_data_seg *dseg, - struct mbuf *mb, int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - - /* copy data into place */ - m_copydata(mb, 0, len, inl + 4); - dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT); - return (dseg); -} - -static void -mlx4_en_store_inline_lso_header(volatile struct mlx4_wqe_data_seg *dseg, - int len, __be32 owner_bit) -{ -} - -static void -mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 index, u8 owner) -{ - struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; - struct mlx4_en_tx_desc *tx_desc = (struct mlx4_en_tx_desc *) - (ring->buf + (index * TXBB_SIZE)); - volatile __be32 *ptr = (__be32 *)tx_desc; - const __be32 stamp = cpu_to_be32(STAMP_VAL | - ((u32)owner << STAMP_SHIFT)); - u32 i; - - /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { - *ptr = stamp; - ptr += STAMP_DWORDS; - } -} - -static u32 -mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 index) -{ - struct mlx4_en_tx_info *tx_info; - struct mbuf *mb; - - tx_info = &ring->tx_info[index]; - mb = tx_info->mb; - - if (mb == NULL) - goto done; - - bus_dmamap_sync(ring->dma_tag, tx_info->dma_map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ring->dma_tag, tx_info->dma_map); - - m_freem(mb); -done: - return (tx_info->nr_txbb); -} - -int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int cnt = 0; - - /* Skip last polled descriptor */ - ring->cons += ring->last_nr_txbb; - en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", - ring->cons, ring->prod); - - if ((u32) (ring->prod - ring->cons) > ring->size) { - en_warn(priv, "Tx consumer passed producer!\n"); - return 0; - } - - while (ring->cons != ring->prod) { - ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, - ring->cons & ring->size_mask); - ring->cons += ring->last_nr_txbb; - cnt++; - } - - if (cnt) - en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); - - return cnt; -} - -static bool -mlx4_en_tx_ring_is_full(struct mlx4_en_tx_ring *ring) -{ - int wqs; - wqs = ring->size - (ring->prod - ring->cons); - return (wqs < (HEADROOM + (2 * MLX4_EN_TX_WQE_MAX_WQEBBS))); -} - -static int mlx4_en_process_tx_cq(struct net_device *dev, - struct mlx4_en_cq *cq) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_cq *mcq = &cq->mcq; - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - struct mlx4_cqe *cqe; - u16 index; - u16 new_index, ring_index, stamp_index; - u32 txbbs_skipped = 0; - u32 txbbs_stamp = 0; - u32 cons_index = mcq->cons_index; - int size = cq->size; - u32 size_mask = ring->size_mask; - struct mlx4_cqe *buf = cq->buf; - int factor = priv->cqe_factor; - - if (!priv->port_up) - return 0; - - index = cons_index & size_mask; - cqe = &buf[(index << factor) + factor]; - ring_index = ring->cons & size_mask; - stamp_index = ring_index; - - /* Process all completed CQEs */ - while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, - cons_index & size)) { - /* - * make sure we read the CQE after we read the - * ownership bit - */ - rmb(); - - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == - MLX4_CQE_OPCODE_ERROR)) { - en_err(priv, "CQE completed in error - vendor syndrom: 0x%x syndrom: 0x%x\n", - ((struct mlx4_err_cqe *)cqe)-> - vendor_err_syndrome, - ((struct mlx4_err_cqe *)cqe)->syndrome); - } - - /* Skip over last polled CQE */ - new_index = be16_to_cpu(cqe->wqe_index) & size_mask; - - do { - txbbs_skipped += ring->last_nr_txbb; - ring_index = (ring_index + ring->last_nr_txbb) & size_mask; - /* free next descriptor */ - ring->last_nr_txbb = mlx4_en_free_tx_desc( - priv, ring, ring_index); - mlx4_en_stamp_wqe(priv, ring, stamp_index, - !!((ring->cons + txbbs_stamp) & - ring->size)); - stamp_index = ring_index; - txbbs_stamp = txbbs_skipped; - } while (ring_index != new_index); - - ++cons_index; - index = cons_index & size_mask; - cqe = &buf[(index << factor) + factor]; - } - - - /* - * To prevent CQ overflow we first update CQ consumer and only then - * the ring consumer. - */ - mcq->cons_index = cons_index; - mlx4_cq_set_ci(mcq); - wmb(); - ring->cons += txbbs_skipped; - - /* Wakeup Tx queue if it was stopped and ring is not full */ - if (unlikely(ring->blocked) && !mlx4_en_tx_ring_is_full(ring)) { - ring->blocked = 0; - if (atomic_fetchadd_int(&priv->blocked, -1) == 1) - atomic_clear_int(&dev->if_drv_flags ,IFF_DRV_OACTIVE); - ring->wake_queue++; - priv->port_stats.wake_queue++; - } - return (0); -} - -void mlx4_en_tx_irq(struct mlx4_cq *mcq) -{ - struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - - if (priv->port_up == 0 || !spin_trylock(&ring->comp_lock)) - return; - mlx4_en_process_tx_cq(cq->dev, cq); - mod_timer(&cq->timer, jiffies + 1); - spin_unlock(&ring->comp_lock); -} - -void mlx4_en_poll_tx_cq(unsigned long data) -{ - struct mlx4_en_cq *cq = (struct mlx4_en_cq *) data; - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - u32 inflight; - - INC_PERF_COUNTER(priv->pstats.tx_poll); - - if (priv->port_up == 0) - return; - if (!spin_trylock(&ring->comp_lock)) { - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - return; - } - mlx4_en_process_tx_cq(cq->dev, cq); - inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); - - /* If there are still packets in flight and the timer has not already - * been scheduled by the Tx routine then schedule it here to guarantee - * completion processing of these packets */ - if (inflight && priv->port_up) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - spin_unlock(&ring->comp_lock); -} - -static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) -{ - struct mlx4_en_cq *cq = priv->tx_cq[tx_ind]; - struct mlx4_en_tx_ring *ring = priv->tx_ring[tx_ind]; - - if (priv->port_up == 0) - return; - - /* If we don't have a pending timer, set one up to catch our recent - post in case the interface becomes idle */ - if (!timer_pending(&cq->timer)) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ - if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - if (spin_trylock(&ring->comp_lock)) { - mlx4_en_process_tx_cq(priv->dev, cq); - spin_unlock(&ring->comp_lock); - } -} - -static u16 -mlx4_en_get_inline_hdr_size(struct mlx4_en_tx_ring *ring, struct mbuf *mb) -{ - u16 retval; - - /* only copy from first fragment, if possible */ - retval = MIN(ring->inline_thold, mb->m_len); - - /* check for too little data */ - if (unlikely(retval < MIN_PKT_LEN)) - retval = MIN(ring->inline_thold, mb->m_pkthdr.len); - return (retval); -} - -static int -mlx4_en_get_header_size(struct mbuf *mb) -{ - struct ether_vlan_header *eh; - struct tcphdr *th; - struct ip *ip; - int ip_hlen, tcp_hlen; - struct ip6_hdr *ip6; - uint16_t eth_type; - int eth_hdr_len; - - eh = mtod(mb, struct ether_vlan_header *); - if (mb->m_len < ETHER_HDR_LEN) - return (0); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - eth_type = ntohs(eh->evl_proto); - eth_hdr_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - eth_type = ntohs(eh->evl_encap_proto); - eth_hdr_len = ETHER_HDR_LEN; - } - if (mb->m_len < eth_hdr_len) - return (0); - switch (eth_type) { - case ETHERTYPE_IP: - ip = (struct ip *)(mb->m_data + eth_hdr_len); - if (mb->m_len < eth_hdr_len + sizeof(*ip)) - return (0); - if (ip->ip_p != IPPROTO_TCP) - return (0); - ip_hlen = ip->ip_hl << 2; - eth_hdr_len += ip_hlen; - break; - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mb->m_data + eth_hdr_len); - if (mb->m_len < eth_hdr_len + sizeof(*ip6)) - return (0); - if (ip6->ip6_nxt != IPPROTO_TCP) - return (0); - eth_hdr_len += sizeof(*ip6); - break; - default: - return (0); - } - if (mb->m_len < eth_hdr_len + sizeof(*th)) - return (0); - th = (struct tcphdr *)(mb->m_data + eth_hdr_len); - tcp_hlen = th->th_off << 2; - eth_hdr_len += tcp_hlen; - if (mb->m_len < eth_hdr_len) - return (0); - return (eth_hdr_len); -} - -static volatile struct mlx4_wqe_data_seg * -mlx4_en_store_inline_data(volatile struct mlx4_wqe_data_seg *dseg, - struct mbuf *mb, int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4; - - if (unlikely(len < MIN_PKT_LEN)) { - m_copydata(mb, 0, len, inl + 4); - memset(inl + 4 + len, 0, MIN_PKT_LEN - len); - dseg += DIV_ROUND_UP(4 + MIN_PKT_LEN, DS_SIZE_ALIGNMENT); - } else if (len <= spc) { - m_copydata(mb, 0, len, inl + 4); - dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT); - } else { - m_copydata(mb, 0, spc, inl + 4); - m_copydata(mb, spc, len - spc, inl + 8 + spc); - dseg += DIV_ROUND_UP(8 + len, DS_SIZE_ALIGNMENT); - } - return (dseg); -} - -static void -mlx4_en_store_inline_header(volatile struct mlx4_wqe_data_seg *dseg, - int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4; - - if (unlikely(len < MIN_PKT_LEN)) { - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | MIN_PKT_LEN); - } else if (len <= spc) { - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | len); - } else { - *(volatile uint32_t *)(inl + 4 + spc) = - SET_BYTE_COUNT((1 << 31) | (len - spc)); - wmb(); - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | spc); - } -} - -static uint32_t hashrandom; -static void hashrandom_init(void *arg) -{ - /* - * It is assumed that the random subsystem has been - * initialized when this function is called: - */ - hashrandom = m_ether_tcpip_hash_init(); -} -SYSINIT(hashrandom_init, SI_SUB_RANDOM, SI_ORDER_ANY, &hashrandom_init, NULL); - -u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - u32 rings_p_up = priv->num_tx_rings_p_up; - u32 up = 0; - u32 queue_index; - -#if (MLX4_EN_NUM_UP > 1) - /* Obtain VLAN information if present */ - if (mb->m_flags & M_VLANTAG) { - u32 vlan_tag = mb->m_pkthdr.ether_vtag; - up = (vlan_tag >> 13) % MLX4_EN_NUM_UP; - } -#endif - queue_index = m_ether_tcpip_hash(MBUF_HASHFLAG_L3 | MBUF_HASHFLAG_L4, mb, hashrandom); - - return ((queue_index % rings_p_up) + (up * rings_p_up)); -} - -static void mlx4_bf_copy(void __iomem *dst, volatile unsigned long *src, unsigned bytecnt) -{ - __iowrite64_copy(dst, __DEVOLATILE(void *, src), bytecnt / 8); -} - -static u64 mlx4_en_mac_to_u64(u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETHER_ADDR_LEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} - -static int mlx4_en_xmit(struct mlx4_en_priv *priv, int tx_ind, struct mbuf **mbp) -{ - enum { - DS_FACT = TXBB_SIZE / DS_SIZE_ALIGNMENT, - CTRL_FLAGS = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | - MLX4_WQE_CTRL_SOLICITED), - }; - bus_dma_segment_t segs[MLX4_EN_TX_MAX_MBUF_FRAGS]; - volatile struct mlx4_wqe_data_seg *dseg; - volatile struct mlx4_wqe_data_seg *dseg_inline; - volatile struct mlx4_en_tx_desc *tx_desc; - struct mlx4_en_tx_ring *ring = priv->tx_ring[tx_ind]; - struct ifnet *ifp = priv->dev; - struct mlx4_en_tx_info *tx_info; - struct mbuf *mb = *mbp; - struct mbuf *m; - __be32 owner_bit; - int nr_segs; - int pad; - int err; - u32 bf_size; - u32 bf_prod; - u32 opcode; - u16 index; - u16 ds_cnt; - u16 ihs; - - if (unlikely(!priv->port_up)) { - err = EINVAL; - goto tx_drop; - } - - /* check if TX ring is full */ - if (unlikely(mlx4_en_tx_ring_is_full(ring))) { - /* every full native Tx ring stops queue */ - if (ring->blocked == 0) - atomic_add_int(&priv->blocked, 1); - /* Set HW-queue-is-full flag */ - atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); - priv->port_stats.queue_stopped++; - ring->blocked = 1; - priv->port_stats.queue_stopped++; - ring->queue_stopped++; - - /* Use interrupts to find out when queue opened */ - mlx4_en_arm_cq(priv, priv->tx_cq[tx_ind]); - return (ENOBUFS); - } - - /* sanity check we are not wrapping around */ - KASSERT(((~ring->prod) & ring->size_mask) >= - (MLX4_EN_TX_WQE_MAX_WQEBBS - 1), ("Wrapping around TX ring")); - - /* Track current inflight packets for performance analysis */ - AVG_PERF_COUNTER(priv->pstats.inflight_avg, - (u32) (ring->prod - ring->cons - 1)); - - /* Track current mbuf packet header length */ - AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, mb->m_pkthdr.len); - - /* Grab an index and try to transmit packet */ - owner_bit = (ring->prod & ring->size) ? - cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0; - index = ring->prod & ring->size_mask; - tx_desc = (volatile struct mlx4_en_tx_desc *) - (ring->buf + index * TXBB_SIZE); - tx_info = &ring->tx_info[index]; - dseg = &tx_desc->data; - - /* send a copy of the frame to the BPF listener, if any */ - if (ifp != NULL && ifp->if_bpf != NULL) - ETHER_BPF_MTAP(ifp, mb); - - /* get default flags */ - tx_desc->ctrl.srcrb_flags = CTRL_FLAGS; - - if (mb->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TSO)) - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM); - - if (mb->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | - CSUM_UDP_IPV6 | CSUM_TCP_IPV6 | CSUM_TSO)) - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM); - - /* do statistics */ - if (likely(tx_desc->ctrl.srcrb_flags != CTRL_FLAGS)) { - priv->port_stats.tx_chksum_offload++; - ring->tx_csum++; - } - - /* check for VLAN tag */ - if (mb->m_flags & M_VLANTAG) { - tx_desc->ctrl.vlan_tag = cpu_to_be16(mb->m_pkthdr.ether_vtag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN; - } else { - tx_desc->ctrl.vlan_tag = 0; - tx_desc->ctrl.ins_vlan = 0; - } - - /* clear immediate field */ - tx_desc->ctrl.imm = 0; - - /* Handle LSO (TSO) packets */ - if (mb->m_pkthdr.csum_flags & CSUM_TSO) { - u32 payload_len; - u32 mss = mb->m_pkthdr.tso_segsz; - u32 num_pkts; - - opcode = cpu_to_be32(MLX4_OPCODE_LSO | MLX4_WQE_CTRL_RR) | - owner_bit; - ihs = mlx4_en_get_header_size(mb); - if (unlikely(ihs > MAX_INLINE)) { - ring->oversized_packets++; - err = EINVAL; - goto tx_drop; - } - tx_desc->lso.mss_hdr_size = cpu_to_be32((mss << 16) | ihs); - payload_len = mb->m_pkthdr.len - ihs; - if (unlikely(payload_len == 0)) - num_pkts = 1; - else - num_pkts = DIV_ROUND_UP(payload_len, mss); - ring->bytes += payload_len + (num_pkts * ihs); - ring->packets += num_pkts; - priv->port_stats.tso_packets++; - /* store pointer to inline header */ - dseg_inline = dseg; - /* copy data inline */ - dseg = mlx4_en_store_inline_lso_data(dseg, - mb, ihs, owner_bit); - } else { - opcode = cpu_to_be32(MLX4_OPCODE_SEND) | - owner_bit; - ihs = mlx4_en_get_inline_hdr_size(ring, mb); - ring->bytes += max_t (unsigned int, - mb->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN); - ring->packets++; - /* store pointer to inline header */ - dseg_inline = dseg; - /* copy data inline */ - dseg = mlx4_en_store_inline_data(dseg, - mb, ihs, owner_bit); - } - m_adj(mb, ihs); - - /* trim off empty mbufs */ - while (mb->m_len == 0) { - mb = m_free(mb); - /* check if all data has been inlined */ - if (mb == NULL) { - nr_segs = 0; - goto skip_dma; - } - } - - err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map, - mb, segs, &nr_segs, BUS_DMA_NOWAIT); - if (unlikely(err == EFBIG)) { - /* Too many mbuf fragments */ - m = m_defrag(mb, M_NOWAIT); - if (m == NULL) { - ring->oversized_packets++; - goto tx_drop; - } - mb = m; - /* Try again */ - err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map, - mb, segs, &nr_segs, BUS_DMA_NOWAIT); - } - /* catch errors */ - if (unlikely(err != 0)) { - ring->oversized_packets++; - goto tx_drop; - } - /* make sure all mbuf data is written to RAM */ - bus_dmamap_sync(ring->dma_tag, tx_info->dma_map, - BUS_DMASYNC_PREWRITE); - -skip_dma: - /* compute number of DS needed */ - ds_cnt = (dseg - ((volatile struct mlx4_wqe_data_seg *)tx_desc)) + nr_segs; - - /* - * Check if the next request can wrap around and fill the end - * of the current request with zero immediate data: - */ - pad = DIV_ROUND_UP(ds_cnt, DS_FACT); - pad = (~(ring->prod + pad)) & ring->size_mask; - - if (unlikely(pad < (MLX4_EN_TX_WQE_MAX_WQEBBS - 1))) { - /* - * Compute the least number of DS blocks we need to - * pad in order to achieve a TX ring wraparound: - */ - pad = (DS_FACT * (pad + 1)); - } else { - /* - * The hardware will automatically jump to the next - * TXBB. No need for padding. - */ - pad = 0; - } - - /* compute total number of DS blocks */ - ds_cnt += pad; - /* - * When modifying this code, please ensure that the following - * computation is always less than or equal to 0x3F: - * - * ((MLX4_EN_TX_WQE_MAX_WQEBBS - 1) * DS_FACT) + - * (MLX4_EN_TX_WQE_MAX_WQEBBS * DS_FACT) - * - * Else the "ds_cnt" variable can become too big. - */ - tx_desc->ctrl.fence_size = (ds_cnt & 0x3f); - - /* store pointer to mbuf */ - tx_info->mb = mb; - tx_info->nr_txbb = DIV_ROUND_UP(ds_cnt, DS_FACT); - bf_size = ds_cnt * DS_SIZE_ALIGNMENT; - bf_prod = ring->prod; - - /* compute end of "dseg" array */ - dseg += nr_segs + pad; - - /* pad using zero immediate dseg */ - while (pad--) { - dseg--; - dseg->addr = 0; - dseg->lkey = 0; - wmb(); - dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0); - } - - /* fill segment list */ - while (nr_segs--) { - if (unlikely(segs[nr_segs].ds_len == 0)) { - dseg--; - dseg->addr = 0; - dseg->lkey = 0; - wmb(); - dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0); - } else { - dseg--; - dseg->addr = cpu_to_be64((uint64_t)segs[nr_segs].ds_addr); - dseg->lkey = cpu_to_be32(priv->mdev->mr.key); - wmb(); - dseg->byte_count = SET_BYTE_COUNT((uint32_t)segs[nr_segs].ds_len); - } - } - - wmb(); - - /* write owner bits in reverse order */ - if ((opcode & cpu_to_be32(0x1F)) == cpu_to_be32(MLX4_OPCODE_LSO)) - mlx4_en_store_inline_lso_header(dseg_inline, ihs, owner_bit); - else - mlx4_en_store_inline_header(dseg_inline, ihs, owner_bit); - - if (unlikely(priv->validate_loopback)) { - /* Copy dst mac address to wqe */ - struct ether_header *ethh; - u64 mac; - u32 mac_l, mac_h; - - ethh = mtod(mb, struct ether_header *); - mac = mlx4_en_mac_to_u64(ethh->ether_dhost); - if (mac) { - mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16); - mac_l = (u32) (mac & 0xffffffff); - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h); - tx_desc->ctrl.imm = cpu_to_be32(mac_l); - } - } - - /* update producer counter */ - ring->prod += tx_info->nr_txbb; - - if (ring->bf_enabled && bf_size <= MAX_BF && - (tx_desc->ctrl.ins_vlan != MLX4_WQE_CTRL_INS_VLAN)) { - - /* store doorbell number */ - *(volatile __be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn); - - /* or in producer number for this WQE */ - opcode |= cpu_to_be32((bf_prod & 0xffff) << 8); - - /* - * Ensure the new descriptor hits memory before - * setting ownership of this descriptor to HW: - */ - wmb(); - tx_desc->ctrl.owner_opcode = opcode; - wmb(); - mlx4_bf_copy(((u8 *)ring->bf.reg) + ring->bf.offset, - (volatile unsigned long *) &tx_desc->ctrl, bf_size); - wmb(); - ring->bf.offset ^= ring->bf.buf_size; - } else { - /* - * Ensure the new descriptor hits memory before - * setting ownership of this descriptor to HW: - */ - wmb(); - tx_desc->ctrl.owner_opcode = opcode; - wmb(); - writel(cpu_to_be32(ring->doorbell_qpn), - ((u8 *)ring->bf.uar->map) + MLX4_SEND_DOORBELL); - } - - return (0); -tx_drop: - *mbp = NULL; - m_freem(mb); - return (err); -} - -static int -mlx4_en_transmit_locked(struct ifnet *dev, int tx_ind, struct mbuf *m) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mbuf *next; - int enqueued, err = 0; - - ring = priv->tx_ring[tx_ind]; - if ((dev->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING || priv->port_up == 0) { - if (m != NULL) - err = drbr_enqueue(dev, ring->br, m); - return (err); - } - - enqueued = 0; - if (m != NULL) - /* - * If we can't insert mbuf into drbr, try to xmit anyway. - * We keep the error we got so we could return that after xmit. - */ - err = drbr_enqueue(dev, ring->br, m); - - /* Process the queue */ - while ((next = drbr_peek(dev, ring->br)) != NULL) { - if (mlx4_en_xmit(priv, tx_ind, &next) != 0) { - if (next == NULL) { - drbr_advance(dev, ring->br); - } else { - drbr_putback(dev, ring->br, next); - } - break; - } - drbr_advance(dev, ring->br); - enqueued++; - if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; - } - - if (enqueued > 0) - ring->watchdog_time = ticks; - - return (err); -} - -void -mlx4_en_tx_que(void *context, int pending) -{ - struct mlx4_en_tx_ring *ring; - struct mlx4_en_priv *priv; - struct net_device *dev; - struct mlx4_en_cq *cq; - int tx_ind; - cq = context; - dev = cq->dev; - priv = dev->if_softc; - tx_ind = cq->ring; - ring = priv->tx_ring[tx_ind]; - - if (priv->port_up != 0 && - (dev->if_drv_flags & IFF_DRV_RUNNING) != 0) { - mlx4_en_xmit_poll(priv, tx_ind); - spin_lock(&ring->tx_lock); - if (!drbr_empty(dev, ring->br)) - mlx4_en_transmit_locked(dev, tx_ind, NULL); - spin_unlock(&ring->tx_lock); - } -} - -int -mlx4_en_transmit(struct ifnet *dev, struct mbuf *m) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mlx4_en_cq *cq; - int i, err = 0; - - if (priv->port_up == 0) { - m_freem(m); - return (ENETDOWN); - } - - /* Compute which queue to use */ - if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { - i = (m->m_pkthdr.flowid % 128) % priv->tx_ring_num; - } - else { - i = mlx4_en_select_queue(dev, m); - } - - ring = priv->tx_ring[i]; - if (spin_trylock(&ring->tx_lock)) { - err = mlx4_en_transmit_locked(dev, i, m); - spin_unlock(&ring->tx_lock); - /* Poll CQ here */ - mlx4_en_xmit_poll(priv, i); - } else { - err = drbr_enqueue(dev, ring->br, m); - cq = priv->tx_cq[i]; - taskqueue_enqueue(cq->tq, &cq->cq_task); - } - - return (err); -} - -/* - * Flush ring buffers. - */ -void -mlx4_en_qflush(struct ifnet *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mbuf *m; - - if (priv->port_up == 0) - return; - - for (int i = 0; i < priv->tx_ring_num; i++) { - ring = priv->tx_ring[i]; - spin_lock(&ring->tx_lock); - while ((m = buf_ring_dequeue_sc(ring->br)) != NULL) - m_freem(m); - spin_unlock(&ring->tx_lock); - } - if_qflush(dev); -} diff --git a/sys/ofed/drivers/net/mlx4/eq.c b/sys/ofed/drivers/net/mlx4/eq.c deleted file mode 100644 index 145b9bc55909..000000000000 --- a/sys/ofed/drivers/net/mlx4/eq.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" -#include "fw.h" - -enum { - MLX4_IRQNAME_SIZE = 32 -}; - -enum { - MLX4_NUM_ASYNC_EQE = 0x100, - MLX4_NUM_SPARE_EQE = 0x80, - MLX4_EQ_ENTRY_SIZE = 0x20 -}; - -#define MLX4_EQ_STATUS_OK ( 0 << 28) -#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) -#define MLX4_EQ_OWNER_SW ( 0 << 24) -#define MLX4_EQ_OWNER_HW ( 1 << 24) -#define MLX4_EQ_FLAG_EC ( 1 << 18) -#define MLX4_EQ_FLAG_OI ( 1 << 17) -#define MLX4_EQ_STATE_ARMED ( 9 << 8) -#define MLX4_EQ_STATE_FIRED (10 << 8) -#define MLX4_EQ_STATE_ALWAYS_ARMED (11 << 8) - -#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG) | \ - (1ull << MLX4_EVENT_TYPE_COMM_EST) | \ - (1ull << MLX4_EVENT_TYPE_SQ_DRAINED) | \ - (1ull << MLX4_EVENT_TYPE_CQ_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ - (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ - (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ - (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) | \ - (1ull << MLX4_EVENT_TYPE_OP_REQUIRED) | \ - (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ - (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ - (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) - -static u64 get_async_ev_mask(struct mlx4_dev *dev) -{ - u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK; - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) - async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT); - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) - async_ev_mask |= (1ull << MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT); - - return async_ev_mask; -} - -static void eq_set_ci(struct mlx4_eq *eq, int req_not) -{ - __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) | - req_not << 31), - eq->doorbell); - /* We still want ordering, just not swabbing, so add a barrier */ - mb(); -} - -static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry, u8 eqe_factor) -{ - /* (entry & (eq->nent - 1)) gives us a cyclic array */ - unsigned long offset = (entry & (eq->nent - 1)) * (MLX4_EQ_ENTRY_SIZE << eqe_factor); - /* CX3 is capable of extending the EQE from 32 to 64 bytes. - * When this feature is enabled, the first (in the lower addresses) - * 32 bytes in the 64 byte EQE are reserved and the next 32 bytes - * contain the legacy EQE information. - */ - return eq->page_list[offset / PAGE_SIZE].buf + (offset + (eqe_factor ? MLX4_EQ_ENTRY_SIZE : 0)) % PAGE_SIZE; -} - -static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq, u8 eqe_factor) -{ - struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index, eqe_factor); - return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; -} - -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 (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_event_eq *slave_eq = &priv->mfunc.master.slave_eq; - struct mlx4_eqe *s_eqe; - unsigned long flags; - - spin_lock_irqsave(&slave_eq->event_lock, flags); - s_eqe = &slave_eq->event_eqe[slave_eq->prod & (SLAVE_EVENT_EQ_SIZE - 1)]; - 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); - spin_unlock_irqrestore(&slave_eq->event_lock, flags); - return; - } - - memcpy(s_eqe, eqe, dev->caps.eqe_size - 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); - spin_unlock_irqrestore(&slave_eq->event_lock, flags); -} - -static void mlx4_slave_event(struct mlx4_dev *dev, int slave, - struct mlx4_eqe *eqe) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (slave < 0 || slave >= dev->num_slaves || - slave == dev->caps.function) - return; - - if (!priv->mfunc.master.slave_state[slave].active) - return; - - slave_event(dev, slave, eqe); -} - -int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_eqe eqe; - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_slave = &priv->mfunc.master.slave_state[slave]; - - if (!s_slave->active) - return 0; - - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE; - eqe.event.port_mgmt_change.port = port; - - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_pkey_eqe); - -int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_eqe eqe; - - /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) - return 0; - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_GUID_INFO; - eqe.event.port_mgmt_change.port = port; - - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_guid_change_eqe); - -int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, - u8 port_subtype_change) -{ - struct mlx4_eqe eqe; - - /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) - return 0; - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_CHANGE; - eqe.subtype = port_subtype_change; - eqe.event.port_change.port = cpu_to_be32(port << 28); - - mlx4_dbg(dev, "%s: sending: %d to slave: %d on port: %d\n", __func__, - port_subtype_change, slave, port); - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_port_state_change_eqe); - -enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return SLAVE_PORT_DOWN; - } - return s_state[slave].port_state[port]; -} -EXPORT_SYMBOL(mlx4_get_slave_port_state); - -static int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, - enum slave_port_state state) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; - - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return -1; - } - s_state[slave].port_state[port] = state; - - return 0; -} - -static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event) -{ - int i; - enum slave_port_gen_event gen_event; - - for (i = 0; i < dev->num_slaves; i++) - set_and_calc_slave_port_state(dev, i, port, event, &gen_event); -} -/************************************************************************** - The function get as input the new event to that port, - and according to the prev state change the slave's port state. - The events are: - MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, - MLX4_PORT_STATE_DEV_EVENT_PORT_UP - MLX4_PORT_STATE_IB_EVENT_GID_VALID - MLX4_PORT_STATE_IB_EVENT_GID_INVALID -***************************************************************************/ -int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, - u8 port, int event, - enum slave_port_gen_event *gen_event) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *ctx = NULL; - unsigned long flags; - int ret = -1; - enum slave_port_state cur_state = - mlx4_get_slave_port_state(dev, slave, port); - - *gen_event = SLAVE_PORT_GEN_EVENT_NONE; - - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return ret; - } - - ctx = &priv->mfunc.master.slave_state[slave]; - spin_lock_irqsave(&ctx->lock, flags); - - switch (cur_state) { - case SLAVE_PORT_DOWN: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_UP == event) - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PENDING_UP); - break; - case SLAVE_PENDING_UP: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_DOWN); - else if (MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID == event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_UP); - *gen_event = SLAVE_PORT_GEN_EVENT_UP; - } - break; - case SLAVE_PORT_UP: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_DOWN); - *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; - } else if (MLX4_PORT_STATE_IB_EVENT_GID_INVALID == - event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PENDING_UP); - *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; - } - break; - default: - pr_err("%s: BUG!!! UNKNOWN state: " - "slave:%d, port:%d\n", __func__, slave, port); - goto out; - } - ret = mlx4_get_slave_port_state(dev, slave, port); - -out: - spin_unlock_irqrestore(&ctx->lock, flags); - return ret; -} - -EXPORT_SYMBOL(set_and_calc_slave_port_state); - -int mlx4_gen_slaves_port_mgt_ev(struct mlx4_dev *dev, u8 port, int attr, u16 sm_lid, u8 sm_sl) -{ - struct mlx4_eqe eqe; - - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PORT_INFO; - eqe.event.port_mgmt_change.port = port; - eqe.event.port_mgmt_change.params.port_info.changed_attr = - cpu_to_be32((u32) attr); - if (attr & MSTR_SM_CHANGE_MASK) { - eqe.event.port_mgmt_change.params.port_info.mstr_sm_lid = - cpu_to_be16(sm_lid); - eqe.event.port_mgmt_change.params.port_info.mstr_sm_sl = - sm_sl; - } - - slave_event(dev, ALL_SLAVES, &eqe); - return 0; -} -EXPORT_SYMBOL(mlx4_gen_slaves_port_mgt_ev); - -void mlx4_master_handle_slave_flr(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, struct mlx4_mfunc_master_ctx, - slave_flr_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_state *slave_state = priv->mfunc.master.slave_state; - int i; - int err; - unsigned long flags; - - mlx4_dbg(dev, "mlx4_handle_slave_flr\n"); - - for (i = 0 ; i < dev->num_slaves; i++) { - - if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) { - mlx4_dbg(dev, "mlx4_handle_slave_flr: " - "clean slave: %d\n", i); - - mlx4_delete_all_resources_for_slave(dev, i); - /*return the slave to running mode*/ - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; - slave_state[i].is_slave_going_down = 0; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - /*notify the FW:*/ - err = mlx4_cmd(dev, 0, i, 0, MLX4_CMD_INFORM_FLR_DONE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to notify FW on " - "FLR done (slave:%d)\n", i); - } - } -} - -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; - int set_ci = 0; - int port; - int slave = 0; - int ret; - u32 flr_slave; - u8 update_slave_state; - int i; - enum slave_port_gen_event gen_event; - unsigned long flags; - struct mlx4_vport_state *s_info; - - while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) { - /* - * Make sure we read EQ entry contents after we've - * checked the ownership bit. - */ - rmb(); - - switch (eqe->type) { - case MLX4_EVENT_TYPE_COMP: - cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; - mlx4_cq_completion(dev, cqn); - break; - - 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_dbg(dev, "event %d arrived\n", eqe->type); - if (mlx4_is_master(dev)) { - /* forward only to slave owning the QP */ - ret = mlx4_get_slave_from_resource_id(dev, - RES_QP, - be32_to_cpu(eqe->event.qp.qpn) - & 0xffffff, &slave); - if (ret && ret != -ENOENT) { - mlx4_dbg(dev, "QP event %02x(%02x) on " - "EQ %d at index %u: could " - "not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - - if (!ret && slave != dev->caps.function) { - mlx4_slave_event(dev, slave, eqe); - break; - } - - } - mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & - 0xffffff, eqe->type); - break; - - case MLX4_EVENT_TYPE_SRQ_LIMIT: - mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", - __func__); - /* fall through */ - case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: - if (mlx4_is_master(dev)) { - /* forward only to slave owning the SRQ */ - ret = mlx4_get_slave_from_resource_id(dev, - RES_SRQ, - be32_to_cpu(eqe->event.srq.srqn) - & 0xffffff, - &slave); - if (ret && ret != -ENOENT) { - mlx4_warn(dev, "SRQ event %02x(%02x) " - "on EQ %d at index %u: could" - " not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - mlx4_dbg(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", - __func__, slave, - be32_to_cpu(eqe->event.srq.srqn), - eqe->type, eqe->subtype); - - if (!ret && slave != dev->caps.function) { - mlx4_dbg(dev, "%s: sending event %02x(%02x) to slave:%d\n", - __func__, eqe->type, - eqe->subtype, slave); - mlx4_slave_event(dev, slave, eqe); - break; - } - } - mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & - 0xffffff, eqe->type); - break; - - case MLX4_EVENT_TYPE_CMD: - mlx4_cmd_event(dev, - be16_to_cpu(eqe->event.cmd.token), - eqe->event.cmd.status, - be64_to_cpu(eqe->event.cmd.out_param)); - break; - - case MLX4_EVENT_TYPE_PORT_CHANGE: - port = be32_to_cpu(eqe->event.port_change.port) >> 28; - if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, - port); - mlx4_priv(dev)->sense.do_sense_port[port] = 1; - if (!mlx4_is_master(dev)) - break; - for (i = 0; i < dev->num_slaves; i++) { - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { - if (i == mlx4_master_func_num(dev)) - continue; - mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN" - " to slave: %d, port:%d\n", - __func__, i, port); - s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state; - if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) - mlx4_slave_event(dev, i, eqe); - } else { /* IB port */ - set_and_calc_slave_port_state(dev, i, port, - MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, - &gen_event); - /*we can be in pending state, then do not send port_down event*/ - if (SLAVE_PORT_GEN_EVENT_DOWN == gen_event) { - if (i == mlx4_master_func_num(dev)) - continue; - mlx4_slave_event(dev, i, eqe); - } - } - } - } else { - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port); - - mlx4_priv(dev)->sense.do_sense_port[port] = 0; - - if (!mlx4_is_master(dev)) - break; - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - for (i = 0; i < dev->num_slaves; i++) { - if (i == mlx4_master_func_num(dev)) - continue; - s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state; - if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) - mlx4_slave_event(dev, i, eqe); - } - else /* IB port */ - /* port-up event will be sent to a slave when the - * slave's alias-guid is set. This is done in alias_GUID.c - */ - set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP); - } - break; - - case MLX4_EVENT_TYPE_CQ_ERROR: - mlx4_warn(dev, "CQ %s on CQN %06x\n", - eqe->event.cq_err.syndrome == 1 ? - "overrun" : "access violation", - be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); - if (mlx4_is_master(dev)) { - ret = mlx4_get_slave_from_resource_id(dev, - RES_CQ, - be32_to_cpu(eqe->event.cq_err.cqn) - & 0xffffff, &slave); - if (ret && ret != -ENOENT) { - mlx4_dbg(dev, "CQ event %02x(%02x) on " - "EQ %d at index %u: could " - "not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - - if (!ret && slave != dev->caps.function) { - mlx4_slave_event(dev, slave, eqe); - break; - } - } - mlx4_cq_event(dev, - be32_to_cpu(eqe->event.cq_err.cqn) - & 0xffffff, - eqe->type); - break; - - case MLX4_EVENT_TYPE_EQ_OVERFLOW: - mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); - break; - - case MLX4_EVENT_TYPE_OP_REQUIRED: - atomic_inc(&priv->opreq_count); - /* FW commands can't be executed from interrupt context - working in deferred task */ - queue_work(mlx4_wq, &priv->opreq_task); - 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 eqe->event.comm_channel_arm.bit_vec); - - if (!queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.comm_work)) - mlx4_warn(dev, "Failed to queue comm channel work\n"); - - if (!queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.arm_comm_work)) - mlx4_warn(dev, "Failed to queue arm comm channel work\n"); - break; - - case MLX4_EVENT_TYPE_FLR_EVENT: - flr_slave = be32_to_cpu(eqe->event.flr_event.slave_id); - if (!mlx4_is_master(dev)) { - mlx4_warn(dev, "Non-master function received" - "FLR event\n"); - break; - } - - mlx4_dbg(dev, "FLR event for slave: %d\n", flr_slave); - - if (flr_slave >= dev->num_slaves) { - mlx4_warn(dev, - "Got FLR for unknown function: %d\n", - flr_slave); - update_slave_state = 0; - } else - update_slave_state = 1; - - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (update_slave_state) { - priv->mfunc.master.slave_state[flr_slave].active = false; - priv->mfunc.master.slave_state[flr_slave].last_cmd = MLX4_COMM_CMD_FLR; - priv->mfunc.master.slave_state[flr_slave].is_slave_going_down = 1; - } - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.slave_flr_event_work); - break; - - case MLX4_EVENT_TYPE_FATAL_WARNING: - if (eqe->subtype == MLX4_FATAL_WARNING_SUBTYPE_WARMING) { - if (mlx4_is_master(dev)) - for (i = 0; i < dev->num_slaves; i++) { - mlx4_dbg(dev, "%s: Sending " - "MLX4_FATAL_WARNING_SUBTYPE_WARMING" - " to slave: %d\n", __func__, i); - if (i == dev->caps.function) - continue; - mlx4_slave_event(dev, i, eqe); - } - mlx4_err(dev, "Temperature Threshold was reached! " - "Threshold: %d celsius degrees; " - "Current Temperature: %d\n", - be16_to_cpu(eqe->event.warming.warning_threshold), - be16_to_cpu(eqe->event.warming.current_temperature)); - } else - mlx4_warn(dev, "Unhandled event FATAL WARNING (%02x), " - "subtype %02x on EQ %d at index %u. owner=%x, " - "nent=0x%x, slave=%x, ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - eqe->slave_id, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - - break; - - case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT: - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, - (unsigned long) eqe); - break; - - case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT: - switch (eqe->subtype) { - case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE: - mlx4_warn(dev, "Bad cable detected on port %u\n", - eqe->event.bad_cable.port); - break; - case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE: - mlx4_warn(dev, "Unsupported cable detected\n"); - break; - default: - mlx4_dbg(dev, "Unhandled recoverable error event " - "detected: %02x(%02x) on EQ %d at index %u. " - "owner=%x, nent=0x%x, ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - break; - } - break; - - case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: - case MLX4_EVENT_TYPE_ECC_DETECT: - default: - mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at " - "index %u. owner=%x, nent=0x%x, slave=%x, " - "ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - eqe->slave_id, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - break; - } - - ++eq->cons_index; - eqes_found = 1; - ++set_ci; - - /* - * The HCA will think the queue has overflowed if we - * don't tell it we've been processing events. We - * create our EQs with MLX4_NUM_SPARE_EQE extra - * entries, so we must update our consumer index at - * least that often. - */ - if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { - eq_set_ci(eq, 0); - set_ci = 0; - } - } - - eq_set_ci(eq, 1); - - return eqes_found; -} - -static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) -{ - struct mlx4_dev *dev = dev_ptr; - struct mlx4_priv *priv = mlx4_priv(dev); - int work = 0; - int i; - - writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); - - return IRQ_RETVAL(work); -} - -static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) -{ - struct mlx4_eq *eq = eq_ptr; - struct mlx4_dev *dev = eq->dev; - - mlx4_eq_int(dev, eq); - - /* MSI-X vectors always belong to us */ - 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_cmd_info *cmd) -{ - 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 & 0x3FF; - u64 in_param = vhcr->in_param; - int err = 0; - int i; - - if (slave == dev->caps.function) - err = mlx4_cmd(dev, in_param, (in_modifier & 0x80000000) | eqn, - 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (!err) - for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) - if (in_param & (1LL << i)) - event_eq[i].eqn = in_modifier >> 31 ? -1 : eqn; - - return err; -} - -static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, - int eq_num) -{ - return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num, - 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} - -static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) -{ - return mlx4_cmd(dev, mailbox->dma, eq_num, 0, - MLX4_CMD_SW2HW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, - 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_num_eq_uar(struct mlx4_dev *dev) -{ - /* - * Each UAR holds 4 EQ doorbells. To figure out how many UARs - * we need to map, take the difference of highest index and - * the lowest index we'll use and add 1. - */ - return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + - dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; -} - -static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int index; - - index = eq->eqn / 4 - dev->caps.reserved_eqs / 4; - - if (!priv->eq_table.uar_map[index]) { - priv->eq_table.uar_map[index] = - ioremap(pci_resource_start(dev->pdev, 2) + - ((eq->eqn / 4) << PAGE_SHIFT), - PAGE_SIZE); - if (!priv->eq_table.uar_map[index]) { - mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n", - eq->eqn); - return NULL; - } - } - - return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); -} - -static void mlx4_unmap_uar(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - for (i = 0; i < mlx4_num_eq_uar(dev); ++i) - if (priv->eq_table.uar_map[i]) { - iounmap(priv->eq_table.uar_map[i]); - priv->eq_table.uar_map[i] = NULL; - } -} - -static int mlx4_create_eq(struct mlx4_dev *dev, int nent, - u8 intr, struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_eq_context *eq_context; - int npages; - u64 *dma_list = NULL; - dma_addr_t t; - u64 mtt_addr; - int err = -ENOMEM; - int i; - - eq->dev = dev; - eq->nent = roundup_pow_of_two(max(nent, 2)); - /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ - npages = PAGE_ALIGN(eq->nent * (MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor)) / PAGE_SIZE; - - eq->page_list = kmalloc(npages * sizeof *eq->page_list, - GFP_KERNEL); - if (!eq->page_list) - goto err_out; - - for (i = 0; i < npages; ++i) - eq->page_list[i].buf = NULL; - - dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); - if (!dma_list) - goto err_out_free; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - goto err_out_free; - eq_context = mailbox->buf; - - for (i = 0; i < npages; ++i) { - eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, - PAGE_SIZE, &t, GFP_KERNEL); - if (!eq->page_list[i].buf) - goto err_out_free_pages; - - dma_list[i] = t; - eq->page_list[i].map = t; - - memset(eq->page_list[i].buf, 0, PAGE_SIZE); - } - - eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap); - if (eq->eqn == -1) - goto err_out_free_pages; - - eq->doorbell = mlx4_get_eq_uar(dev, eq); - if (!eq->doorbell) { - err = -ENOMEM; - goto err_out_free_eq; - } - - err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt); - if (err) - goto err_out_free_eq; - - err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list); - if (err) - goto err_out_free_mtt; - - memset(eq_context, 0, sizeof *eq_context); - eq_context->flags = cpu_to_be32(MLX4_EQ_STATUS_OK | - MLX4_EQ_STATE_ARMED); - eq_context->log_eq_size = ilog2(eq->nent); - eq_context->intr = intr; - eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, &eq->mtt); - eq_context->mtt_base_addr_h = mtt_addr >> 32; - eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - - err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn); - if (err) { - mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err); - goto err_out_free_mtt; - } - - kfree(dma_list); - mlx4_free_cmd_mailbox(dev, mailbox); - - eq->cons_index = 0; - - return err; - -err_out_free_mtt: - mlx4_mtt_cleanup(dev, &eq->mtt); - -err_out_free_eq: - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - -err_out_free_pages: - for (i = 0; i < npages; ++i) - if (eq->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); - - mlx4_free_cmd_mailbox(dev, mailbox); - -err_out_free: - kfree(eq->page_list); - kfree(dma_list); - -err_out: - return err; -} - -static void mlx4_free_eq(struct mlx4_dev *dev, - struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - int err; - int i; - /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ - int npages = PAGE_ALIGN((MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor) * eq->nent) / PAGE_SIZE; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return; - - err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); - if (err) - mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); - - if (0) { - mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); - for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { - if (i % 4 == 0) - pr_cont("[%02x] ", i * 4); - pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4)); - if ((i + 1) % 4 == 0) - pr_cont("\n"); - } - } - - mlx4_mtt_cleanup(dev, &eq->mtt); - for (i = 0; i < npages; ++i) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); - - kfree(eq->page_list); - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - mlx4_free_cmd_mailbox(dev, mailbox); -} - -static void mlx4_free_irqs(struct mlx4_dev *dev) -{ - struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; - struct mlx4_priv *priv = mlx4_priv(dev); - int i, vec; - - if (eq_table->have_irq) - free_irq(dev->pdev->irq, dev); - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - if (eq_table->eq[i].have_irq) { - free_irq(eq_table->eq[i].irq, eq_table->eq + i); - eq_table->eq[i].have_irq = 0; - } - - for (i = 0; i < dev->caps.comp_pool; i++) { - /* - * Freeing the assigned irq's - * all bits should be 0, but we need to validate - */ - if (priv->msix_ctl.pool_bm & 1ULL << i) { - /* NO need protecting*/ - vec = dev->caps.num_comp_vectors + 1 + i; - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - } - } - - - kfree(eq_table->irq_names); -} - -static int mlx4_map_clr_int(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + - priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); - if (!priv->clr_base) { - mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n"); - return -ENOMEM; - } - - return 0; -} - -static void mlx4_unmap_clr_int(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - iounmap(priv->clr_base); -} - -int mlx4_alloc_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs, - sizeof *priv->eq_table.eq, GFP_KERNEL); - if (!priv->eq_table.eq) - return -ENOMEM; - - return 0; -} - -void mlx4_free_eq_table(struct mlx4_dev *dev) -{ - kfree(mlx4_priv(dev)->eq_table.eq); -} - -int mlx4_init_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int i; - - priv->eq_table.uar_map = kcalloc(mlx4_num_eq_uar(dev), - sizeof *priv->eq_table.uar_map, - GFP_KERNEL); - if (!priv->eq_table.uar_map) { - err = -ENOMEM; - goto err_out_free; - } - - err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, - dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0); - if (err) - goto err_out_free; - - for (i = 0; i < mlx4_num_eq_uar(dev); ++i) - priv->eq_table.uar_map[i] = NULL; - - if (!mlx4_is_slave(dev)) { - err = mlx4_map_clr_int(dev); - if (err) - goto err_out_bitmap; - - priv->eq_table.clr_mask = - swab32(1 << (priv->eq_table.inta_pin & 31)); - priv->eq_table.clr_int = priv->clr_base + - (priv->eq_table.inta_pin < 32 ? 4 : 0); - } - - priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + - dev->caps.comp_pool), - GFP_KERNEL); - if (!priv->eq_table.irq_names) { - err = -ENOMEM; - goto err_out_clr_int; - } - - for (i = 0; i < dev->caps.num_comp_vectors; ++i) { - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; - } - } - - 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 additional completion vectors poolsize is 0 this loop will not run*/ - for (i = dev->caps.num_comp_vectors + 1; - i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { - - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; - } - } - - - if (dev->flags & MLX4_FLAG_MSI_X) { - const char *eq_name; - - 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, - MLX4_IRQNAME_SIZE, - "mlx4-comp-%d@pci:%s", i, - pci_name(dev->pdev)); - } else { - snprintf(priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, - "mlx4-async@pci:%s", - pci_name(dev->pdev)); - } - - eq_name = priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE; - err = request_irq(priv->eq_table.eq[i].irq, - mlx4_msi_x_interrupt, 0, eq_name, - priv->eq_table.eq + i); - if (err) - goto err_out_async; - - priv->eq_table.eq[i].have_irq = 1; - } - } else { - snprintf(priv->eq_table.irq_names, - MLX4_IRQNAME_SIZE, - DRV_NAME "@pci:%s", - pci_name(dev->pdev)); - err = request_irq(dev->pdev->irq, mlx4_interrupt, - IRQF_SHARED, priv->eq_table.irq_names, dev); - if (err) - goto err_out_async; - - priv->eq_table.have_irq = 1; - } - - err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 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 + 1; ++i) - eq_set_ci(&priv->eq_table.eq[i], 1); - - return 0; - -err_out_async: - mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); - -err_out_comp: - i = dev->caps.num_comp_vectors - 1; - -err_out_unmap: - while (i >= 0) { - mlx4_free_eq(dev, &priv->eq_table.eq[i]); - --i; - } - mlx4_free_irqs(dev); - -err_out_clr_int: - if (!mlx4_is_slave(dev)) - mlx4_unmap_clr_int(dev); - -err_out_bitmap: - mlx4_unmap_uar(dev); - mlx4_bitmap_cleanup(&priv->eq_table.bitmap); - -err_out_free: - kfree(priv->eq_table.uar_map); - - return err; -} - -void mlx4_cleanup_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 1, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - - mlx4_free_irqs(dev); - - for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) - mlx4_free_eq(dev, &priv->eq_table.eq[i]); - - if (!mlx4_is_slave(dev)) - mlx4_unmap_clr_int(dev); - - mlx4_unmap_uar(dev); - mlx4_bitmap_cleanup(&priv->eq_table.bitmap); - - kfree(priv->eq_table.uar_map); -} - -/* A test that verifies that we can accept interrupts on all - * the irq vectors of the device. - * Interrupts are checked using the NOP command. - */ -int mlx4_test_interrupts(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - int err; - - err = mlx4_NOP(dev); - /* When not in MSI_X, there is only one irq to check */ - if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev)) - return err; - - /* A loop over all completion vectors, for each vector we will check - * whether it works by mapping command completions to that vector - * and performing a NOP command - */ - for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { - /* Temporary use polling for command completions */ - mlx4_cmd_use_polling(dev); - - /* Map the new eq to handle all asyncronous events */ - err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[i].eqn); - if (err) { - mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); - mlx4_cmd_use_events(dev); - break; - } - - /* Go back to using events */ - mlx4_cmd_use_events(dev); - err = mlx4_NOP(dev); - } - - /* Return to default */ - mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - return err; -} -EXPORT_SYMBOL(mlx4_test_interrupts); - -int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) -{ - - struct mlx4_priv *priv = mlx4_priv(dev); - int vec = 0, err = 0, i; - - mutex_lock(&priv->msix_ctl.pool_lock); - for (i = 0; !vec && i < dev->caps.comp_pool; i++) { - if (~priv->msix_ctl.pool_bm & 1ULL << i) { - priv->msix_ctl.pool_bm |= 1ULL << i; - vec = dev->caps.num_comp_vectors + 1 + i; - snprintf(priv->eq_table.irq_names + - vec * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, "%s", name); - err = request_irq(priv->eq_table.eq[vec].irq, - mlx4_msi_x_interrupt, 0, - &priv->eq_table.irq_names[vec<<5], - priv->eq_table.eq + vec); - if (err) { - /*zero out bit by fliping it*/ - priv->msix_ctl.pool_bm ^= 1 << i; - vec = 0; - continue; - /*we dont want to break here*/ - } - eq_set_ci(&priv->eq_table.eq[vec], 1); - } - } - mutex_unlock(&priv->msix_ctl.pool_lock); - - if (vec) { - *vector = vec; - } else { - *vector = 0; - err = (i == dev->caps.comp_pool) ? -ENOSPC : err; - } - return err; -} -EXPORT_SYMBOL(mlx4_assign_eq); - -void mlx4_release_eq(struct mlx4_dev *dev, int vec) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - /*bm index*/ - int i = vec - dev->caps.num_comp_vectors - 1; - - if (likely(i >= 0)) { - /*sanity check , making sure were not trying to free irq's - Belonging to a legacy EQ*/ - mutex_lock(&priv->msix_ctl.pool_lock); - if (priv->msix_ctl.pool_bm & 1ULL << i) { - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - priv->msix_ctl.pool_bm &= ~(1ULL << i); - } - mutex_unlock(&priv->msix_ctl.pool_lock); - } - -} -EXPORT_SYMBOL(mlx4_release_eq); - diff --git a/sys/ofed/drivers/net/mlx4/fw.c b/sys/ofed/drivers/net/mlx4/fw.c deleted file mode 100644 index e2909fa60f89..000000000000 --- a/sys/ofed/drivers/net/mlx4/fw.c +++ /dev/null @@ -1,1956 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/etherdevice.h> -#include <linux/mlx4/cmd.h> -#include <linux/module.h> -#include <linux/cache.h> - -#include "fw.h" -#include "icm.h" - -enum { - MLX4_COMMAND_INTERFACE_MIN_REV = 2, - MLX4_COMMAND_INTERFACE_MAX_REV = 3, - MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS = 3, -}; - -extern void __buggy_use_of_MLX4_GET(void); -extern void __buggy_use_of_MLX4_PUT(void); - -static u8 enable_qos; -module_param(enable_qos, byte, 0444); -MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)"); - -#define MLX4_GET(dest, source, offset) \ - do { \ - void *__p = (char *) (source) + (offset); \ - switch (sizeof (dest)) { \ - case 1: (dest) = *(u8 *) __p; break; \ - case 2: (dest) = be16_to_cpup(__p); break; \ - case 4: (dest) = be32_to_cpup(__p); break; \ - case 8: (dest) = be64_to_cpup(__p); break; \ - default: __buggy_use_of_MLX4_GET(); \ - } \ - } while (0) - -#define MLX4_PUT(dest, source, offset) \ - do { \ - void *__d = ((char *) (dest) + (offset)); \ - switch (sizeof(source)) { \ - case 1: *(u8 *) __d = (source); break; \ - case 2: *(__be16 *) __d = cpu_to_be16(source); break; \ - case 4: *(__be32 *) __d = cpu_to_be32(source); break; \ - case 8: *(__be64 *) __d = cpu_to_be64(source); break; \ - default: __buggy_use_of_MLX4_PUT(); \ - } \ - } while (0) - -static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) -{ - static const char *fname[] = { - [ 0] = "RC transport", - [ 1] = "UC transport", - [ 2] = "UD transport", - [ 3] = "XRC transport", - [ 4] = "reliable multicast", - [ 5] = "FCoIB support", - [ 6] = "SRQ support", - [ 7] = "IPoIB checksum offload", - [ 8] = "P_Key violation counter", - [ 9] = "Q_Key violation counter", - [10] = "VMM", - [12] = "DPDP", - [15] = "Big LSO headers", - [16] = "MW support", - [17] = "APM support", - [18] = "Atomic ops support", - [19] = "Raw multicast support", - [20] = "Address vector port checking support", - [21] = "UD multicast support", - [24] = "Demand paging support", - [25] = "Router support", - [30] = "IBoE support", - [32] = "Unicast loopback support", - [34] = "FCS header control", - [38] = "Wake On LAN support", - [40] = "UDP RSS support", - [41] = "Unicast VEP steering support", - [42] = "Multicast VEP steering support", - [44] = "Cross-channel (sync_qp) operations support", - [48] = "Counters support", - [59] = "Port management change event support", - [60] = "eSwitch support", - [61] = "64 byte EQE support", - [62] = "64 byte CQE support", - }; - int i; - - mlx4_dbg(dev, "DEV_CAP flags:\n"); - for (i = 0; i < ARRAY_SIZE(fname); ++i) - if (fname[i] && (flags & (1LL << i))) - mlx4_dbg(dev, " %s\n", fname[i]); -} - -static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) -{ - static const char * const fname[] = { - [0] = "RSS support", - [1] = "RSS Toeplitz Hash Function support", - [2] = "RSS XOR Hash Function support", - [3] = "Device manage flow steering support", - [4] = "FSM (MAC unti-spoofing) support", - [5] = "VST (control vlan insertion/stripping) support", - [6] = "Dynamic QP updates support", - [7] = "Loopback source checks support", - [8] = "Device managed flow steering IPoIB support", - [9] = "ETS configuration support", - [10] = "ETH backplane autoneg report", - [11] = "Ethernet Flow control statistics support", - [12] = "Recoverable error events support", - [13] = "Time stamping support", - [14] = "Report driver version to FW support" - }; - int i; - - for (i = 0; i < ARRAY_SIZE(fname); ++i) - if (fname[i] && (flags & (1LL << i))) - mlx4_dbg(dev, " %s\n", fname[i]); -} - -int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *inbox; - int err = 0; - -#define MOD_STAT_CFG_IN_SIZE 0x100 - -#define MOD_STAT_CFG_PG_SZ_M_OFFSET 0x002 -#define MOD_STAT_CFG_PG_SZ_OFFSET 0x003 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, MOD_STAT_CFG_IN_SIZE); - - MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET); - MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u8 field, port; - u32 size; - int err = 0; - -#define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0 -#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET 0x1 -#define QUERY_FUNC_CAP_PF_BHVR_OFFSET 0x4 -#define QUERY_FUNC_CAP_FMR_OFFSET 0x8 -#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP 0x10 -#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP 0x14 -#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP 0x18 -#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP 0x20 -#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP 0x24 -#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28 -#define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c -#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30 - -#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50 -#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54 -#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET 0x58 -#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET 0x60 -#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET 0x64 -#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET 0x68 - -#define QUERY_FUNC_CAP_FMR_FLAG 0x80 -#define QUERY_FUNC_CAP_FLAG_RDMA 0x40 -#define QUERY_FUNC_CAP_FLAG_ETH 0x80 -#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10 - -/* when opcode modifier = 1 */ -#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3 -#define QUERY_FUNC_CAP_FLAGS0_OFFSET 0x8 -#define QUERY_FUNC_CAP_FLAGS1_OFFSET 0xc -#define QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET 0xd - -#define QUERY_FUNC_CAP_QP0_TUNNEL 0x10 -#define QUERY_FUNC_CAP_QP0_PROXY 0x14 -#define QUERY_FUNC_CAP_QP1_TUNNEL 0x18 -#define QUERY_FUNC_CAP_QP1_PROXY 0x1c - -#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC 0x40 -#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN 0x80 -#define QUERY_FUNC_CAP_PROPS_DEF_COUNTER 0x20 - -#define QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID 0x80 - - if (vhcr->op_modifier == 1) { - port = vhcr->in_modifier; /* phys-port = logical-port */ - MLX4_PUT(outbox->buf, port, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); - - field = 0; - /* ensure that phy_wqe_gid bit is not set */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET); - - /* ensure force vlan and force mac bits are not set - * and that default counter bit is set - */ - field = QUERY_FUNC_CAP_PROPS_DEF_COUNTER; /* def counter */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET); - - /* There is always default counter legal or sink counter */ - field = mlx4_get_default_counter_index(dev, slave, vhcr->in_modifier); - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET); - - /* size is now the QP number */ - size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL); - - size += 2; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL); - - size = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_PROXY); - - size += 2; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY); - - } else if (vhcr->op_modifier == 0) { - /* enable rdma and ethernet interfaces, and new quota locations */ - field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | - QUERY_FUNC_CAP_FLAG_QUOTAS); - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); - - field = dev->caps.num_ports; - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); - - size = dev->caps.function_caps; /* set PF behaviours */ - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_PF_BHVR_OFFSET); - - field = 0; /* protected FMR support not available as yet */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FMR_OFFSET); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); - size = dev->caps.num_qps; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); - size = dev->caps.num_srqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); - size = dev->caps.num_cqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); - - size = dev->caps.num_eqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET); - - size = dev->caps.reserved_eqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); - size = dev->caps.num_mpts; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); - size = dev->caps.num_mtts; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); - - size = dev->caps.num_mgms + dev->caps.num_amgms; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); - - } else - err = -EINVAL; - - return err; -} - -int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port, - struct mlx4_func_cap *func_cap) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u8 field, op_modifier; - u32 size; - int err = 0, quotas = 0; - - op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */ - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, gen_or_port, op_modifier, - MLX4_CMD_QUERY_FUNC_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - goto out; - - outbox = mailbox->buf; - - if (!op_modifier) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS_OFFSET); - if (!(field & (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA))) { - mlx4_err(dev, "The host supports neither eth nor rdma interfaces\n"); - err = -EPROTONOSUPPORT; - goto out; - } - func_cap->flags = field; - quotas = !!(func_cap->flags & QUERY_FUNC_CAP_FLAG_QUOTAS); - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); - func_cap->num_ports = field; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_PF_BHVR_OFFSET); - func_cap->pf_context_behaviour = size; - - if (quotas) { - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); - func_cap->qp_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); - func_cap->srq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); - func_cap->cq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); - func_cap->mpt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); - func_cap->mtt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); - func_cap->mcg_quota = size & 0xFFFFFF; - - } else { - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); - func_cap->qp_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); - func_cap->srq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); - func_cap->cq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); - func_cap->mpt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); - func_cap->mtt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); - func_cap->mcg_quota = size & 0xFFFFFF; - } - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MAX_EQ_OFFSET); - func_cap->max_eq = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); - func_cap->reserved_eq = size & 0xFFFFFF; - - goto out; - } - - /* logical port query */ - if (gen_or_port > dev->caps.num_ports) { - err = -EINVAL; - goto out; - } - - if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); - if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN) { - mlx4_err(dev, "VLAN is enforced on this port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - - if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC) { - mlx4_err(dev, "Force mac is enabled on this port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - } else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); - if (field & QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID) { - mlx4_err(dev, "phy_wqe_gid is " - "enforced on this ib port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - } - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); - func_cap->physical_port = field; - if (func_cap->physical_port != gen_or_port) { - err = -ENOSYS; - goto out; - } - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); - if (field & QUERY_FUNC_CAP_PROPS_DEF_COUNTER) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET); - func_cap->def_counter_index = field; - } else { - func_cap->def_counter_index = MLX4_SINK_COUNTER_INDEX; - } - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL); - func_cap->qp0_tunnel_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_PROXY); - func_cap->qp0_proxy_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_TUNNEL); - func_cap->qp1_tunnel_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY); - func_cap->qp1_proxy_qpn = size & 0xFFFFFF; - - /* All other resources are allocated by the master, but we still report - * 'num' and 'reserved' capabilities as follows: - * - num remains the maximum resource index - * - 'num - reserved' is the total available objects of a resource, but - * resource indices may be less than 'reserved' - * TODO: set per-resource quotas */ - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; -} - -int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u8 field; - u32 field32, flags, ext_flags; - u16 size; - u16 stat_rate; - int err; - int i; - -#define QUERY_DEV_CAP_OUT_SIZE 0x100 -#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET 0x10 -#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET 0x11 -#define QUERY_DEV_CAP_RSVD_QP_OFFSET 0x12 -#define QUERY_DEV_CAP_MAX_QP_OFFSET 0x13 -#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET 0x14 -#define QUERY_DEV_CAP_MAX_SRQ_OFFSET 0x15 -#define QUERY_DEV_CAP_RSVD_EEC_OFFSET 0x16 -#define QUERY_DEV_CAP_MAX_EEC_OFFSET 0x17 -#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET 0x19 -#define QUERY_DEV_CAP_RSVD_CQ_OFFSET 0x1a -#define QUERY_DEV_CAP_MAX_CQ_OFFSET 0x1b -#define QUERY_DEV_CAP_MAX_MPT_OFFSET 0x1d -#define QUERY_DEV_CAP_RSVD_EQ_OFFSET 0x1e -#define QUERY_DEV_CAP_MAX_EQ_OFFSET 0x1f -#define QUERY_DEV_CAP_RSVD_MTT_OFFSET 0x20 -#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21 -#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22 -#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23 -#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 -#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 -#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b -#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d -#define QUERY_DEV_CAP_RSS_OFFSET 0x2e -#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f -#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 -#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 -#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 -#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 -#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38 -#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b -#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c -#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET 0x3e -#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f -#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET 0x40 -#define QUERY_DEV_CAP_SYNC_QP_OFFSET 0x42 -#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 -#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 -#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 -#define QUERY_DEV_CAP_PAGE_SZ_OFFSET 0x4b -#define QUERY_DEV_CAP_BF_OFFSET 0x4c -#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET 0x4d -#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e -#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f -#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET 0x51 -#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52 -#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55 -#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56 -#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61 -#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62 -#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63 -#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 -#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 -#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66 -#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67 -#define QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET 0x68 -#define QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET 0x6c -#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET 0x70 -#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76 -#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET 0x70 -#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET 0x74 -#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77 -#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 -#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 -#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 -#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET 0x86 -#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET 0x88 -#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET 0x8a -#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET 0x8c -#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET 0x8e -#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90 -#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 -#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 -#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 -#define QUERY_DEV_CAP_ETS_CFG_OFFSET 0x9c -#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 - - dev_cap->flags2 = 0; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET); - dev_cap->reserved_qps = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); - dev_cap->max_qps = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET); - dev_cap->reserved_srqs = 1 << (field >> 4); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET); - dev_cap->max_srqs = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET); - dev_cap->max_cq_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET); - dev_cap->reserved_cqs = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET); - dev_cap->max_cqs = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET); - dev_cap->max_mpts = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); - dev_cap->reserved_eqs = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); - dev_cap->max_eqs = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); - dev_cap->reserved_mtts = 1 << (field >> 4); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); - dev_cap->max_mrw_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET); - dev_cap->reserved_mrws = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET); - dev_cap->max_mtt_seg = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET); - dev_cap->max_requester_per_qp = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); - dev_cap->max_responder_per_qp = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); - field &= 0x1f; - if (!field) - dev_cap->max_gso_sz = 0; - else - dev_cap->max_gso_sz = 1 << field; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET); - if (field & 0x20) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR; - if (field & 0x10) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP; - field &= 0xf; - if (field) { - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS; - dev_cap->max_rss_tbl_sz = 1 << field; - } else - dev_cap->max_rss_tbl_sz = 0; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); - dev_cap->max_rdma_global = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); - dev_cap->local_ca_ack_delay = field & 0x1f; - MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); - dev_cap->num_ports = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET); - dev_cap->max_msg_sz = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET); - if (field & 0x10) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB; - dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET); - dev_cap->fs_max_num_qp_per_entry = field; - MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); - dev_cap->stat_rate_support = stat_rate; - MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS; - MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); - dev_cap->flags = flags | (u64)ext_flags << 32; - MLX4_GET(field, outbox, QUERY_DEV_CAP_SYNC_QP_OFFSET); - dev_cap->sync_qp = field & 0x10; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); - dev_cap->reserved_uars = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET); - dev_cap->uar_size = 1 << ((field & 0x3f) + 20); - MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET); - dev_cap->min_page_sz = 1 << field; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET); - if (field & 0x80) { - MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); - dev_cap->bf_reg_size = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); - if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) - field = 3; - dev_cap->bf_regs_per_page = 1 << (field & 0x3f); - mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", - dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); - } else { - dev_cap->bf_reg_size = 0; - mlx4_dbg(dev, "BlueFlame not available\n"); - } - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET); - dev_cap->max_sq_sg = field; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET); - dev_cap->max_sq_desc_sz = size; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET); - dev_cap->max_qp_per_mcg = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET); - dev_cap->reserved_mgms = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET); - dev_cap->max_mcgs = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET); - dev_cap->reserved_pds = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET); - dev_cap->max_pds = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET); - dev_cap->reserved_xrcds = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET); - dev_cap->max_xrcds = 1 << (field & 0x1f); - - MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET); - dev_cap->rdmarc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET); - dev_cap->qpc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET); - dev_cap->aux_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET); - dev_cap->altc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET); - dev_cap->eqc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET); - dev_cap->cqc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET); - dev_cap->srq_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET); - dev_cap->cmpt_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET); - dev_cap->mtt_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET); - dev_cap->dmpt_entry_sz = size; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET); - dev_cap->max_srq_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET); - dev_cap->max_qp_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET); - dev_cap->resize_srq = field & 1; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET); - dev_cap->max_rq_sg = field; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); - dev_cap->max_rq_desc_sz = size; - - MLX4_GET(dev_cap->bmme_flags, outbox, - QUERY_DEV_CAP_BMME_FLAGS_OFFSET); - MLX4_GET(dev_cap->reserved_lkey, outbox, - QUERY_DEV_CAP_RSVD_LKEY_OFFSET); - MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETS_CFG_OFFSET); - if (field32 & (1 << 0)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP; - if (field32 & (1 << 7)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT; - if (field32 & (1 << 8)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW; - if (field32 & (1 << 13)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG; - - MLX4_GET(dev_cap->max_icm_sz, outbox, - QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); - if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS) - MLX4_GET(dev_cap->max_basic_counters, outbox, - QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET); - /* FW reports 256 however real value is 255 */ - dev_cap->max_basic_counters = min_t(u32, dev_cap->max_basic_counters, 255); - if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS_EXT) - MLX4_GET(dev_cap->max_extended_counters, outbox, - QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET); - - MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); - if (field32 & (1 << 16)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP; - if (field32 & (1 << 19)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK; - if (field32 & (1 << 20)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM; - if (field32 & (1 << 26)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL; - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - for (i = 1; i <= dev_cap->num_ports; ++i) { - MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); - dev_cap->max_vl[i] = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET); - dev_cap->ib_mtu[i] = field >> 4; - dev_cap->max_port_width[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET); - dev_cap->max_gids[i] = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET); - dev_cap->max_pkeys[i] = 1 << (field & 0xf); - } - } else { -#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00 -#define QUERY_PORT_MTU_OFFSET 0x01 -#define QUERY_PORT_ETH_MTU_OFFSET 0x02 -#define QUERY_PORT_WIDTH_OFFSET 0x06 -#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07 -#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a -#define QUERY_PORT_MAX_VL_OFFSET 0x0b -#define QUERY_PORT_MAC_OFFSET 0x10 -#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18 -#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c -#define QUERY_PORT_TRANS_CODE_OFFSET 0x20 - - for (i = 1; i <= dev_cap->num_ports; ++i) { - err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET); - dev_cap->supported_port_types[i] = field & 3; - dev_cap->suggested_type[i] = (field >> 3) & 1; - dev_cap->default_sense[i] = (field >> 4) & 1; - MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); - dev_cap->ib_mtu[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); - dev_cap->max_port_width[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET); - dev_cap->max_gids[i] = 1 << (field >> 4); - dev_cap->max_pkeys[i] = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); - dev_cap->max_vl[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); - dev_cap->log_max_macs[i] = field & 0xf; - dev_cap->log_max_vlans[i] = field >> 4; - MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET); - MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET); - MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET); - dev_cap->trans_type[i] = field32 >> 24; - dev_cap->vendor_oui[i] = field32 & 0xffffff; - MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET); - MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET); - } - } - - mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n", - dev_cap->bmme_flags, dev_cap->reserved_lkey); - - /* - * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then - * we can't use any EQs whose doorbell falls on that page, - * even if the EQ itself isn't reserved. - */ - dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4, - dev_cap->reserved_eqs); - - mlx4_dbg(dev, "Max ICM size %lld MB\n", - (unsigned long long) dev_cap->max_icm_sz >> 20); - mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", - dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz); - mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", - dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz); - mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", - dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz); - mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n", - dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz); - mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", - dev_cap->reserved_mrws, dev_cap->reserved_mtts); - mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", - dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars); - mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", - dev_cap->max_pds, dev_cap->reserved_mgms); - mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", - dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz); - mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n", - dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1], - dev_cap->max_port_width[1]); - mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n", - dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); - mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", - dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); - mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); - mlx4_dbg(dev, "Max basic counters: %d\n", dev_cap->max_basic_counters); - mlx4_dbg(dev, "Max extended counters: %d\n", dev_cap->max_extended_counters); - mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz); - - dump_dev_cap_flags(dev, dev_cap->flags); - dump_dev_cap_flags2(dev, dev_cap->flags2); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u64 flags; - int err = 0; - u8 field; - - err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - - /* add port mng change event capability unconditionally to slaves */ - MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV; - MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - - /* For guests, report Blueflame disabled */ - MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET); - field &= 0x7f; - MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET); - - /* turn off device-managed steering capability if not enabled */ - if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) { - MLX4_GET(field, outbox->buf, - QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - field &= 0x7f; - MLX4_PUT(outbox->buf, field, - QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - } - return 0; -} - -int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 def_mac; - u8 port_type; - u16 short_field; - int err; - int admin_link_state; - -#define MLX4_VF_PORT_NO_LINK_SENSE_MASK 0xE0 -#define MLX4_PORT_LINK_UP_MASK 0x80 -#define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c -#define QUERY_PORT_CUR_MAX_GID_OFFSET 0x0e - - err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - - if (!err && dev->caps.function != slave) { - /* set slave default_mac address to be zero MAC */ - def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; - MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); - - /* get port type - currently only eth is enabled */ - MLX4_GET(port_type, outbox->buf, - QUERY_PORT_SUPPORTED_TYPE_OFFSET); - - /* No link sensing allowed */ - port_type &= MLX4_VF_PORT_NO_LINK_SENSE_MASK; - /* set port type to currently operating port type */ - port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3); - - admin_link_state = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.link_state; - if (IFLA_VF_LINK_STATE_ENABLE == admin_link_state) - port_type |= MLX4_PORT_LINK_UP_MASK; - else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state) - port_type &= ~MLX4_PORT_LINK_UP_MASK; - - MLX4_PUT(outbox->buf, port_type, - QUERY_PORT_SUPPORTED_TYPE_OFFSET); - - if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH) - short_field = mlx4_get_slave_num_gids(dev, slave); - else - short_field = 1; /* slave max gids */ - MLX4_PUT(outbox->buf, short_field, - QUERY_PORT_CUR_MAX_GID_OFFSET); - - short_field = dev->caps.pkey_table_len[vhcr->in_modifier]; - MLX4_PUT(outbox->buf, short_field, - QUERY_PORT_CUR_MAX_PKEY_OFFSET); - } - - return err; -} - -int mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port, - int *gid_tbl_len, int *pkey_tbl_len) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u16 field; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - goto out; - - outbox = mailbox->buf; - - MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_GID_OFFSET); - *gid_tbl_len = field; - - MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_PKEY_OFFSET); - *pkey_tbl_len = field; - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_get_slave_pkey_gid_tbl_len); - -int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_icm_iter iter; - __be64 *pages; - int lg; - int nent = 0; - int i; - int err = 0; - int ts = 0, tc = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); - pages = mailbox->buf; - - for (mlx4_icm_first(icm, &iter); - !mlx4_icm_last(&iter); - mlx4_icm_next(&iter)) { - /* - * We have to pass pages that are aligned to their - * size, so find the least significant 1 in the - * address or size and use that as our log2 size. - */ - lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1; - if (lg < MLX4_ICM_PAGE_SHIFT) { - mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n", - MLX4_ICM_PAGE_SIZE, - (unsigned long long) mlx4_icm_addr(&iter), - mlx4_icm_size(&iter)); - err = -EINVAL; - goto out; - } - - for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) { - if (virt != -1) { - pages[nent * 2] = cpu_to_be64(virt); - virt += 1 << lg; - } - - pages[nent * 2 + 1] = - cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) | - (lg - MLX4_ICM_PAGE_SHIFT)); - ts += 1 << (lg - 10); - ++tc; - - if (++nent == MLX4_MAILBOX_SIZE / 16) { - err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, - MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (err) - goto out; - nent = 0; - } - } - } - - if (nent) - err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - goto out; - - switch (op) { - case MLX4_CMD_MAP_FA: - mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts); - break; - case MLX4_CMD_MAP_ICM_AUX: - mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts); - break; - case MLX4_CMD_MAP_ICM: - mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n", - tc, ts, (unsigned long long) virt - (ts << 10)); - break; - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1); -} - -int mlx4_UNMAP_FA(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - - -int mlx4_RUN_FW(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -int mlx4_QUERY_FW(struct mlx4_dev *dev) -{ - struct mlx4_fw *fw = &mlx4_priv(dev)->fw; - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int err = 0; - u64 fw_ver; - u16 cmd_if_rev; - u8 lg; - -#define QUERY_FW_OUT_SIZE 0x100 -#define QUERY_FW_VER_OFFSET 0x00 -#define QUERY_FW_PPF_ID 0x09 -#define QUERY_FW_CMD_IF_REV_OFFSET 0x0a -#define QUERY_FW_MAX_CMD_OFFSET 0x0f -#define QUERY_FW_ERR_START_OFFSET 0x30 -#define QUERY_FW_ERR_SIZE_OFFSET 0x38 -#define QUERY_FW_ERR_BAR_OFFSET 0x3c - -#define QUERY_FW_SIZE_OFFSET 0x00 -#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 -#define QUERY_FW_CLR_INT_BAR_OFFSET 0x28 - -#define QUERY_FW_COMM_BASE_OFFSET 0x40 -#define QUERY_FW_COMM_BAR_OFFSET 0x48 - -#define QUERY_FW_CLOCK_OFFSET 0x50 -#define QUERY_FW_CLOCK_BAR 0x58 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET); - /* - * FW subminor version is at more significant bits than minor - * version, so swap here. - */ - dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) | - ((fw_ver & 0xffff0000ull) >> 16) | - ((fw_ver & 0x0000ffffull) << 16); - - MLX4_GET(lg, outbox, QUERY_FW_PPF_ID); - dev->caps.function = lg; - - if (mlx4_is_slave(dev)) - goto out; - - - MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET); - if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV || - cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) { - mlx4_err(dev, "Installed FW has unsupported " - "command interface revision %d.\n", - cmd_if_rev); - mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n", - (int) (dev->caps.fw_ver >> 32), - (int) (dev->caps.fw_ver >> 16) & 0xffff, - (int) dev->caps.fw_ver & 0xffff); - mlx4_err(dev, "This driver version supports only revisions %d to %d.\n", - MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV); - err = -ENODEV; - goto out; - } - - if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS) - dev->flags |= MLX4_FLAG_OLD_PORT_CMDS; - - MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); - cmd->max_cmds = 1 << lg; - - mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n", - (int) (dev->caps.fw_ver >> 32), - (int) (dev->caps.fw_ver >> 16) & 0xffff, - (int) dev->caps.fw_ver & 0xffff, - cmd_if_rev, cmd->max_cmds); - - MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET); - MLX4_GET(fw->catas_size, outbox, QUERY_FW_ERR_SIZE_OFFSET); - MLX4_GET(fw->catas_bar, outbox, QUERY_FW_ERR_BAR_OFFSET); - fw->catas_bar = (fw->catas_bar >> 6) * 2; - - mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n", - (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar); - - MLX4_GET(fw->fw_pages, outbox, QUERY_FW_SIZE_OFFSET); - MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); - MLX4_GET(fw->clr_int_bar, outbox, QUERY_FW_CLR_INT_BAR_OFFSET); - fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2; - - MLX4_GET(fw->comm_base, outbox, QUERY_FW_COMM_BASE_OFFSET); - MLX4_GET(fw->comm_bar, outbox, QUERY_FW_COMM_BAR_OFFSET); - fw->comm_bar = (fw->comm_bar >> 6) * 2; - mlx4_dbg(dev, "Communication vector bar:%d offset:0x%llx\n", - fw->comm_bar, (unsigned long long)fw->comm_base); - mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2); - - MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET); - MLX4_GET(fw->clock_bar, outbox, QUERY_FW_CLOCK_BAR); - fw->clock_bar = (fw->clock_bar >> 6) * 2; - mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n", - fw->comm_bar, (unsigned long long)fw->comm_base); - - /* - * Round up number of system pages needed in case - * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. - */ - fw->fw_pages = - ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> - (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); - - mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n", - (unsigned long long) fw->clr_int_base, fw->clr_int_bar); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u8 *outbuf; - int err; - - outbuf = outbox->buf; - err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - - /* for slaves, set pci PPF ID to invalid and zero out everything - * else except FW version */ - outbuf[0] = outbuf[1] = 0; - memset(&outbuf[8], 0, QUERY_FW_OUT_SIZE - 8); - outbuf[QUERY_FW_PPF_ID] = MLX4_INVALID_SLAVE_ID; - - return 0; -} - -static void get_board_id(void *vsd, char *board_id, char *vsdstr) -{ - int i; - -#define VSD_OFFSET_SIG1 0x00 -#define VSD_OFFSET_SIG2 0xde -#define VSD_OFFSET_MLX_BOARD_ID 0xd0 -#define VSD_OFFSET_TS_BOARD_ID 0x20 -#define VSD_LEN 0xd0 - -#define VSD_SIGNATURE_TOPSPIN 0x5ad - - memset(vsdstr, 0, MLX4_VSD_LEN); - - for (i = 0; i < VSD_LEN / 4; i++) - ((u32 *)vsdstr)[i] = - swab32(*(u32 *)(vsd + i * 4)); - - memset(board_id, 0, MLX4_BOARD_ID_LEN); - - if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && - be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { - strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN); - } else { - /* - * The board ID is a string but the firmware byte - * swaps each 4-byte word before passing it back to - * us. Therefore we need to swab it before printing. - */ - for (i = 0; i < 4; ++i) - ((u32 *) board_id)[i] = - swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); - } -} - -int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int err; - -#define QUERY_ADAPTER_OUT_SIZE 0x100 -#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 -#define QUERY_ADAPTER_VSD_OFFSET 0x20 -#define QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET 0x1e - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); - - adapter->vsd_vendor_id = be16_to_cpup((u16 *)outbox + - QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET / 2); - - get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4, - adapter->board_id, adapter->vsd); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) -{ - struct mlx4_cmd_mailbox *mailbox; - __be32 *inbox; - u32 mw_enable; - int err; - -#define INIT_HCA_IN_SIZE 0x200 -#define INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE 64 -#define INIT_HCA_VERSION_OFFSET 0x000 -#define INIT_HCA_VERSION 2 -#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e -#define INIT_HCA_FLAGS_OFFSET 0x014 -#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018 -#define INIT_HCA_QPC_OFFSET 0x020 -#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) -#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) -#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) -#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) -#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) -#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) -#define INIT_HCA_EQE_CQE_OFFSETS (INIT_HCA_QPC_OFFSET + 0x38) -#define INIT_HCA_ALTC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) -#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) -#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) -#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) -#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) -#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77) -#define INIT_HCA_MCAST_OFFSET 0x0c0 -#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) -#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) -#define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) -#define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) -#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) -#define INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN 0x6 -#define INIT_HCA_DRIVER_VERSION_OFFSET 0x140 -#define INIT_HCA_FS_PARAM_OFFSET 0x1d0 -#define INIT_HCA_FS_BASE_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x00) -#define INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x12) -#define INIT_HCA_FS_LOG_TABLE_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x1b) -#define INIT_HCA_FS_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21) -#define INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22) -#define INIT_HCA_FS_IB_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x25) -#define INIT_HCA_FS_IB_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x26) -#define INIT_HCA_TPT_OFFSET 0x0f0 -#define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) -#define INIT_HCA_TPT_MW_OFFSET (INIT_HCA_TPT_OFFSET + 0x08) -#define INIT_HCA_TPT_MW_ENABLE (1 << 31) -#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) -#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) -#define INIT_HCA_CMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x18) -#define INIT_HCA_UAR_OFFSET 0x120 -#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) -#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, INIT_HCA_IN_SIZE); - - *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION; - - *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) = - ((ilog2(cache_line_size()) - 4) << 5) | (1 << 4); - -#if defined(__LITTLE_ENDIAN) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1); -#elif defined(__BIG_ENDIAN) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1); -#else -#error Host endianness not defined -#endif - /* Check port for UD address vector: */ - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); - - /* Enable IPoIB checksumming if we can: */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); - - /* Enable QoS support if module parameter set */ - if (enable_qos) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); - - /* Enable fast drop performance optimization */ - if (dev->caps.fast_drop) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 7); - - /* enable counters */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4); - - /* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) { - *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29); - dev->caps.eqe_size = 64; - dev->caps.eqe_factor = 1; - } else { - dev->caps.eqe_size = 32; - dev->caps.eqe_factor = 0; - } - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_CQE) { - *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 30); - dev->caps.cqe_size = 64; - dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_64B_CQE; - } else { - dev->caps.cqe_size = 32; - } - - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) - *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31); - - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW) { - strncpy((u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET, - DRV_NAME_FOR_FW, - INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE - 1); - mlx4_dbg(dev, "Reporting Driver Version to FW: %s\n", - (u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET); - } - - /* QPC/EEC/CQC/EQC/RDMARC attributes */ - - MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); - MLX4_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); - MLX4_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); - MLX4_PUT(inbox, param->altc_base, INIT_HCA_ALTC_BASE_OFFSET); - MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET); - MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); - MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET); - - /* steering attributes */ - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= - cpu_to_be32(1 << - INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN); - - MLX4_PUT(inbox, param->mc_base, INIT_HCA_FS_BASE_OFFSET); - MLX4_PUT(inbox, param->log_mc_entry_sz, - INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_table_sz, - INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); - /* Enable Ethernet flow steering - * with udp unicast and tcp unicast - */ - MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), - INIT_HCA_FS_ETH_BITS_OFFSET); - MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, - INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET); - /* Enable IPoIB flow steering - * with udp unicast and tcp unicast - */ - MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), - INIT_HCA_FS_IB_BITS_OFFSET); - MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, - INIT_HCA_FS_IB_NUM_ADDRS_OFFSET); - } else { - MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_mc_entry_sz, - INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_hash_sz, - INIT_HCA_LOG_MC_HASH_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_table_sz, - INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); - if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0) - MLX4_PUT(inbox, (u8) (1 << 3), - INIT_HCA_UC_STEERING_OFFSET); - } - - /* TPT attributes */ - - MLX4_PUT(inbox, param->dmpt_base, INIT_HCA_DMPT_BASE_OFFSET); - mw_enable = param->mw_enable ? INIT_HCA_TPT_MW_ENABLE : 0; - MLX4_PUT(inbox, mw_enable, INIT_HCA_TPT_MW_OFFSET); - MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); - MLX4_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); - MLX4_PUT(inbox, param->cmpt_base, INIT_HCA_CMPT_BASE_OFFSET); - - /* UAR attributes */ - - MLX4_PUT(inbox, param->uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); - MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000, - MLX4_CMD_NATIVE); - - if (err) - mlx4_err(dev, "INIT_HCA returns %d\n", err); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_HCA(struct mlx4_dev *dev, - struct mlx4_init_hca_param *param) -{ - struct mlx4_cmd_mailbox *mailbox; - __be32 *outbox; - u32 dword_field; - u32 mw_enable; - int err; - u8 byte_field; - -#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04 -#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, - MLX4_CMD_QUERY_HCA, - MLX4_CMD_TIME_CLASS_B, - !mlx4_is_slave(dev)); - if (err) - goto out; - - MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET); - MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); - - /* QPC/EEC/CQC/EQC/RDMARC attributes */ - - MLX4_GET(param->qpc_base, outbox, INIT_HCA_QPC_BASE_OFFSET); - MLX4_GET(param->log_num_qps, outbox, INIT_HCA_LOG_QP_OFFSET); - MLX4_GET(param->srqc_base, outbox, INIT_HCA_SRQC_BASE_OFFSET); - MLX4_GET(param->log_num_srqs, outbox, INIT_HCA_LOG_SRQ_OFFSET); - MLX4_GET(param->cqc_base, outbox, INIT_HCA_CQC_BASE_OFFSET); - MLX4_GET(param->log_num_cqs, outbox, INIT_HCA_LOG_CQ_OFFSET); - MLX4_GET(param->altc_base, outbox, INIT_HCA_ALTC_BASE_OFFSET); - MLX4_GET(param->auxc_base, outbox, INIT_HCA_AUXC_BASE_OFFSET); - MLX4_GET(param->eqc_base, outbox, INIT_HCA_EQC_BASE_OFFSET); - MLX4_GET(param->log_num_eqs, outbox, INIT_HCA_LOG_EQ_OFFSET); - MLX4_GET(param->rdmarc_base, outbox, INIT_HCA_RDMARC_BASE_OFFSET); - MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET); - - MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET); - if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) { - param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED; - } else { - MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET); - if (byte_field & 0x8) - param->steering_mode = MLX4_STEERING_MODE_B0; - else - param->steering_mode = MLX4_STEERING_MODE_A0; - } - /* steering attributes */ - if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { - MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); - } else { - MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_hash_sz, outbox, - INIT_HCA_LOG_MC_HASH_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); - } - - /* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */ - MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_OFFSETS); - if (byte_field & 0x20) /* 64-bytes eqe enabled */ - param->dev_cap_enabled |= MLX4_DEV_CAP_64B_EQE_ENABLED; - if (byte_field & 0x40) /* 64-bytes cqe enabled */ - param->dev_cap_enabled |= MLX4_DEV_CAP_64B_CQE_ENABLED; - - /* TPT attributes */ - - MLX4_GET(param->dmpt_base, outbox, INIT_HCA_DMPT_BASE_OFFSET); - MLX4_GET(mw_enable, outbox, INIT_HCA_TPT_MW_OFFSET); - param->mw_enable = (mw_enable & INIT_HCA_TPT_MW_ENABLE) == - INIT_HCA_TPT_MW_ENABLE; - MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET); - MLX4_GET(param->mtt_base, outbox, INIT_HCA_MTT_BASE_OFFSET); - MLX4_GET(param->cmpt_base, outbox, INIT_HCA_CMPT_BASE_OFFSET); - - /* UAR attributes */ - - MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); - MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; -} - -/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0 - * and real QP0 are active, so that the paravirtualized QP0 is ready - * to operate */ -static int check_qp0_state(struct mlx4_dev *dev, int function, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - /* irrelevant if not infiniband */ - if (priv->mfunc.master.qp0_state[port].proxy_qp0_active && - priv->mfunc.master.qp0_state[port].qp0_active) - return 1; - return 0; -} - -int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int port = vhcr->in_modifier; - int err; - - if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port)) - return 0; - - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { - /* Enable port only if it was previously disabled */ - if (!priv->mfunc.master.init_port_ref[port]) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - } - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } else { - if (slave == mlx4_master_func_num(dev)) { - if (check_qp0_state(dev, slave, port) && - !priv->mfunc.master.qp0_state[port].port_active) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - priv->mfunc.master.qp0_state[port].port_active = 1; - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } - } else - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } - ++priv->mfunc.master.init_port_ref[port]; - return 0; -} - -int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *inbox; - int err; - u32 flags; - u16 field; - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { -#define INIT_PORT_IN_SIZE 256 -#define INIT_PORT_FLAGS_OFFSET 0x00 -#define INIT_PORT_FLAG_SIG (1 << 18) -#define INIT_PORT_FLAG_NG (1 << 17) -#define INIT_PORT_FLAG_G0 (1 << 16) -#define INIT_PORT_VL_SHIFT 4 -#define INIT_PORT_PORT_WIDTH_SHIFT 8 -#define INIT_PORT_MTU_OFFSET 0x04 -#define INIT_PORT_MAX_GID_OFFSET 0x06 -#define INIT_PORT_MAX_PKEY_OFFSET 0x0a -#define INIT_PORT_GUID0_OFFSET 0x10 -#define INIT_PORT_NODE_GUID_OFFSET 0x18 -#define INIT_PORT_SI_GUID_OFFSET 0x20 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, INIT_PORT_IN_SIZE); - - flags = 0; - flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT; - flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT; - MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET); - - field = 128 << dev->caps.ib_mtu_cap[port]; - MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET); - field = dev->caps.gid_table_len[port]; - MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET); - field = dev->caps.pkey_table_len[port]; - MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - } else - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); - -int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int port = vhcr->in_modifier; - int err; - - if (!(priv->mfunc.master.slave_state[slave].init_port_mask & - (1 << port))) - return 0; - - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { - if (priv->mfunc.master.init_port_ref[port] == 1) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); - if (err) - return err; - } - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - } else { - /* infiniband port */ - if (slave == mlx4_master_func_num(dev)) { - if (!priv->mfunc.master.qp0_state[port].qp0_active && - priv->mfunc.master.qp0_state[port].port_active) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); - if (err) - return err; - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - priv->mfunc.master.qp0_state[port].port_active = 0; - } - } else - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - } - --priv->mfunc.master.init_port_ref[port]; - return 0; -} - -int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) -{ - return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000, - MLX4_CMD_WRAPPED); -} -EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); - -int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) -{ - return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000, - MLX4_CMD_NATIVE); -} - -int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) -{ - int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0, - MLX4_CMD_SET_ICM_SIZE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (ret) - return ret; - - /* - * Round up number of system pages needed in case - * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. - */ - *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> - (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); - - return 0; -} - -int mlx4_NOP(struct mlx4_dev *dev) -{ - /* Input modifier of 0x1f means "finish as soon as possible." */ - return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -int mlx4_query_diag_counters(struct mlx4_dev *dev, int array_length, - u8 op_modifier, u32 in_offset[], - u32 counter_out[]) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int ret; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - ret = mlx4_cmd_box(dev, 0, mailbox->dma, 0, op_modifier, - MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (ret) - goto out; - - for (i = 0; i < array_length; i++) { - if (in_offset[i] > MLX4_MAILBOX_SIZE) { - ret = -EINVAL; - goto out; - } - - MLX4_GET(counter_out[i], outbox, in_offset[i]); - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_query_diag_counters); - -int mlx4_MOD_STAT_CFG_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -#define MLX4_WOL_SETUP_MODE (5 << 28) -int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) -{ - u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; - - return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, - MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_wol_read); - -int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) -{ - u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; - - return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_wol_write); - -enum { - ADD_TO_MCG = 0x26, -}; - - -void mlx4_opreq_action(struct work_struct *work) -{ - struct mlx4_priv *priv = container_of(work, struct mlx4_priv, opreq_task); - struct mlx4_dev *dev = &priv->dev; - int num_tasks = atomic_read(&priv->opreq_count); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 *outbox; - u32 modifier; - u16 token; - u16 type_m; - u16 type; - int err; - u32 num_qps; - struct mlx4_qp qp; - int i; - u8 rem_mcg; - u8 prot; - -#define GET_OP_REQ_MODIFIER_OFFSET 0x08 -#define GET_OP_REQ_TOKEN_OFFSET 0x14 -#define GET_OP_REQ_TYPE_OFFSET 0x1a -#define GET_OP_REQ_DATA_OFFSET 0x20 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n"); - return; - } - outbox = mailbox->buf; - - while (num_tasks) { - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, - MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) { - mlx4_err(dev, "Failed to retrieve required operation: %d\n", err); - return; - } - MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET); - MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET); - MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET); - type_m = type >> 12; - type &= 0xfff; - - switch (type) { - case ADD_TO_MCG: - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { - mlx4_warn(dev, "ADD MCG operation is not supported in " - "DEVICE_MANAGED steerign mode\n"); - err = EPERM; - break; - } - mgm = (struct mlx4_mgm *) ((u8 *) (outbox) + GET_OP_REQ_DATA_OFFSET); - num_qps = be32_to_cpu(mgm->members_count) & MGM_QPN_MASK; - rem_mcg = ((u8 *) (&mgm->members_count))[0] & 1; - prot = ((u8 *) (&mgm->members_count))[0] >> 6; - - for (i = 0; i < num_qps; i++) { - qp.qpn = be32_to_cpu(mgm->qp[i]); - if (rem_mcg) - err = mlx4_multicast_detach(dev, &qp, mgm->gid, prot, 0); - else - err = mlx4_multicast_attach(dev, &qp, mgm->gid, mgm->gid[5] ,0, prot, NULL); - if (err) - break; - } - break; - default: - mlx4_warn(dev, "Bad type for required operation\n"); - err = EINVAL; - break; - } - err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16), 1, - MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) { - mlx4_err(dev, "Failed to acknowledge required request: %d\n", err); - goto out; - } - memset(outbox, 0, 0xffc); - num_tasks = atomic_dec_return(&priv->opreq_count); - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); -} diff --git a/sys/ofed/drivers/net/mlx4/fw.h b/sys/ofed/drivers/net/mlx4/fw.h deleted file mode 100644 index 0efd047ec3ad..000000000000 --- a/sys/ofed/drivers/net/mlx4/fw.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef MLX4_FW_H -#define MLX4_FW_H - -#include "mlx4.h" -#include "icm.h" - -struct mlx4_mod_stat_cfg { - u8 log_pg_sz; - u8 log_pg_sz_m; -}; - -struct mlx4_dev_cap { - int max_srq_sz; - int max_qp_sz; - int reserved_qps; - int max_qps; - int reserved_srqs; - int max_srqs; - int max_cq_sz; - int reserved_cqs; - int max_cqs; - int max_mpts; - int reserved_eqs; - int max_eqs; - int reserved_mtts; - int max_mrw_sz; - int reserved_mrws; - int max_mtt_seg; - int max_requester_per_qp; - int max_responder_per_qp; - int max_rdma_global; - int local_ca_ack_delay; - int num_ports; - u32 max_msg_sz; - int ib_mtu[MLX4_MAX_PORTS + 1]; - int max_port_width[MLX4_MAX_PORTS + 1]; - int max_vl[MLX4_MAX_PORTS + 1]; - int max_gids[MLX4_MAX_PORTS + 1]; - int max_pkeys[MLX4_MAX_PORTS + 1]; - u64 def_mac[MLX4_MAX_PORTS + 1]; - u16 eth_mtu[MLX4_MAX_PORTS + 1]; - int trans_type[MLX4_MAX_PORTS + 1]; - int vendor_oui[MLX4_MAX_PORTS + 1]; - u16 wavelength[MLX4_MAX_PORTS + 1]; - u64 trans_code[MLX4_MAX_PORTS + 1]; - u16 stat_rate_support; - int fs_log_max_ucast_qp_range_size; - int fs_max_num_qp_per_entry; - u64 flags; - u64 flags2; - int reserved_uars; - int uar_size; - int min_page_sz; - int bf_reg_size; - int bf_regs_per_page; - int max_sq_sg; - int max_sq_desc_sz; - int max_rq_sg; - int max_rq_desc_sz; - int max_qp_per_mcg; - int reserved_mgms; - int max_mcgs; - int reserved_pds; - int max_pds; - int reserved_xrcds; - int max_xrcds; - int qpc_entry_sz; - int rdmarc_entry_sz; - int altc_entry_sz; - int aux_entry_sz; - int srq_entry_sz; - int cqc_entry_sz; - int eqc_entry_sz; - int dmpt_entry_sz; - int cmpt_entry_sz; - int mtt_entry_sz; - int resize_srq; - u32 bmme_flags; - u32 reserved_lkey; - u64 max_icm_sz; - int max_gso_sz; - int max_rss_tbl_sz; - u8 supported_port_types[MLX4_MAX_PORTS + 1]; - u8 suggested_type[MLX4_MAX_PORTS + 1]; - u8 default_sense[MLX4_MAX_PORTS + 1]; - u8 log_max_macs[MLX4_MAX_PORTS + 1]; - u8 log_max_vlans[MLX4_MAX_PORTS + 1]; - u32 max_basic_counters; - u32 sync_qp; - u8 timestamp_support; - u32 max_extended_counters; -}; - -struct mlx4_func_cap { - u8 num_ports; - u8 flags; - u32 pf_context_behaviour; - int qp_quota; - int cq_quota; - int srq_quota; - int mpt_quota; - int mtt_quota; - int max_eq; - int reserved_eq; - int mcg_quota; - u32 qp0_tunnel_qpn; - u32 qp0_proxy_qpn; - u32 qp1_tunnel_qpn; - u32 qp1_proxy_qpn; - u8 physical_port; - u8 port_flags; - u8 def_counter_index; -}; - -struct mlx4_adapter { - u16 vsd_vendor_id; - char board_id[MLX4_BOARD_ID_LEN]; - char vsd[MLX4_VSD_LEN]; - u8 inta_pin; -}; - -struct mlx4_init_hca_param { - u64 qpc_base; - u64 rdmarc_base; - u64 auxc_base; - u64 altc_base; - u64 srqc_base; - u64 cqc_base; - u64 eqc_base; - u64 mc_base; - u64 dmpt_base; - u64 cmpt_base; - u64 mtt_base; - u64 global_caps; - u16 log_mc_entry_sz; - u16 log_mc_hash_sz; - u16 hca_core_clock; - u8 log_num_qps; - u8 log_num_srqs; - u8 log_num_cqs; - u8 log_num_eqs; - u8 log_rd_per_qp; - u8 log_mc_table_sz; - u8 log_mpt_sz; - u8 log_uar_sz; - u8 uar_page_sz; /* log pg sz in 4k chunks */ - u8 mw_enable; /* Enable memory windows */ - u8 fs_hash_enable_bits; - u8 steering_mode; /* for QUERY_HCA */ - u64 dev_cap_enabled; -}; - -struct mlx4_init_ib_param { - int port_width; - int vl_cap; - int mtu_cap; - u16 gid_cap; - u16 pkey_cap; - int set_guid0; - u64 guid0; - int set_node_guid; - u64 node_guid; - int set_si_guid; - u64 si_guid; -}; - -struct mlx4_set_ib_param { - int set_si_guid; - int reset_qkey_viol; - u64 si_guid; - u32 cap_mask; -}; - -int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap); -int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port, - struct mlx4_func_cap *func_cap); -int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm); -int mlx4_UNMAP_FA(struct mlx4_dev *dev); -int mlx4_RUN_FW(struct mlx4_dev *dev); -int mlx4_QUERY_FW(struct mlx4_dev *dev); -int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter); -int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); -int mlx4_QUERY_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); -int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic); -int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt); -int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages); -int mlx4_NOP(struct mlx4_dev *dev); -int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg); -void mlx4_opreq_action(struct work_struct *work); - -#endif /* MLX4_FW_H */ diff --git a/sys/ofed/drivers/net/mlx4/icm.c b/sys/ofed/drivers/net/mlx4/icm.c deleted file mode 100644 index 25ae7b7fb8cc..000000000000 --- a/sys/ofed/drivers/net/mlx4/icm.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> -#include <linux/math64.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" -#include "icm.h" -#include "fw.h" - -/* - * We allocate in as big chunks as we can, up to a maximum of 256 KB - * per chunk. - */ -enum { - MLX4_ICM_ALLOC_SIZE = 1 << 18, - MLX4_TABLE_CHUNK_SIZE = 1 << 18 -}; - -static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) -{ - int i; - - if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < chunk->npages; ++i) - __free_pages(sg_page(&chunk->mem[i]), - get_order(chunk->mem[i].length)); -} - -static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) -{ - int i; - - for (i = 0; i < chunk->npages; ++i) - dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, - lowmem_page_address(sg_page(&chunk->mem[i])), - sg_dma_address(&chunk->mem[i])); -} - -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) -{ - struct mlx4_icm_chunk *chunk, *tmp; - - if (!icm) - return; - - list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { - if (coherent) - mlx4_free_icm_coherent(dev, chunk); - else - mlx4_free_icm_pages(dev, chunk); - - kfree(chunk); - } - - kfree(icm); -} - -static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, - gfp_t gfp_mask, int node) -{ - struct page *page; - - page = alloc_pages_node(node, gfp_mask, order); - if (!page) { - page = alloc_pages(gfp_mask, order); - if (!page) - return -ENOMEM; - } - - sg_set_page(mem, page, PAGE_SIZE << order, 0); - return 0; -} - -static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, - int order, gfp_t gfp_mask) -{ - void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, - &sg_dma_address(mem), gfp_mask); - if (!buf) - return -ENOMEM; - - sg_set_buf(mem, buf, PAGE_SIZE << order); - BUG_ON(mem->offset); - sg_dma_len(mem) = PAGE_SIZE << order; - return 0; -} - -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask, int coherent) -{ - struct mlx4_icm *icm; - struct mlx4_icm_chunk *chunk = NULL; - int cur_order; - int ret; - - /* We use sg_set_buf for coherent allocs, which assumes low memory */ - BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); - - icm = kmalloc_node(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN), - dev->numa_node); - if (!icm) { - icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); - if (!icm) - return NULL; - } - - icm->refcount = 0; - INIT_LIST_HEAD(&icm->chunk_list); - - cur_order = get_order(MLX4_ICM_ALLOC_SIZE); - - while (npages > 0) { - if (!chunk) { - chunk = kmalloc_node(sizeof *chunk, - gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN), - dev->numa_node); - if (!chunk) { - chunk = kmalloc(sizeof *chunk, - gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); - if (!chunk) - goto fail; - } - - sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN); - chunk->npages = 0; - chunk->nsg = 0; - list_add_tail(&chunk->list, &icm->chunk_list); - } - - while (1 << cur_order > npages) - --cur_order; - - if (coherent) - ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, - &chunk->mem[chunk->npages], - cur_order, gfp_mask); - else - ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], - cur_order, gfp_mask, - dev->numa_node); - - if (ret) { - if (--cur_order < 0) - goto fail; - else - continue; - } - - ++chunk->npages; - - if (coherent) - ++chunk->nsg; - else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - if (chunk->nsg <= 0) - goto fail; - } - - if (chunk->npages == MLX4_ICM_CHUNK_LEN) - chunk = NULL; - - npages -= 1 << cur_order; - } - - if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - if (chunk->nsg <= 0) - goto fail; - } - - return icm; - -fail: - mlx4_free_icm(dev, icm, coherent); - return NULL; -} - -static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt); -} - -static int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count) -{ - return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, -1); -} - -int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_ICM_AUX, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) -{ - u32 i = (obj & (table->num_obj - 1)) / - (MLX4_TABLE_CHUNK_SIZE / table->obj_size); - int ret = 0; - - mutex_lock(&table->mutex); - - if (table->icm[i]) { - ++table->icm[i]->refcount; - goto out; - } - - table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, - (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN, table->coherent); - if (!table->icm[i]) { - ret = -ENOMEM; - goto out; - } - - if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + - (u64) i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i], table->coherent); - table->icm[i] = NULL; - ret = -ENOMEM; - goto out; - } - - ++table->icm[i]->refcount; - -out: - mutex_unlock(&table->mutex); - return ret; -} - -void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) -{ - u32 i; - u64 offset; - - i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); - - mutex_lock(&table->mutex); - - if (--table->icm[i]->refcount == 0) { - offset = (u64) i * MLX4_TABLE_CHUNK_SIZE; - - if (!mlx4_UNMAP_ICM(dev, table->virt + offset, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE)) { - mlx4_free_icm(dev, table->icm[i], table->coherent); - table->icm[i] = NULL; - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - } - } - - mutex_unlock(&table->mutex); -} - -void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, - dma_addr_t *dma_handle) -{ - int offset, dma_offset, i; - u64 idx; - struct mlx4_icm_chunk *chunk; - struct mlx4_icm *icm; - struct page *page = NULL; - - if (!table->lowmem) - return NULL; - - mutex_lock(&table->mutex); - - idx = (u64) (obj & (table->num_obj - 1)) * table->obj_size; - icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; - dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; - - if (!icm) - goto out; - - list_for_each_entry(chunk, &icm->chunk_list, list) { - for (i = 0; i < chunk->npages; ++i) { - if (dma_handle && dma_offset >= 0) { - if (sg_dma_len(&chunk->mem[i]) > dma_offset) - *dma_handle = sg_dma_address(&chunk->mem[i]) + - dma_offset; - dma_offset -= sg_dma_len(&chunk->mem[i]); - } - /* - * DMA mapping can merge pages but not split them, - * so if we found the page, dma_handle has already - * been assigned to. - */ - if (chunk->mem[i].length > offset) { - page = sg_page(&chunk->mem[i]); - goto out; - } - offset -= chunk->mem[i].length; - } - } - -out: - mutex_unlock(&table->mutex); - return page ? lowmem_page_address(page) + offset : NULL; -} - -int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end) -{ - int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; - int err; - u32 i; - - for (i = start; i <= end; i += inc) { - err = mlx4_table_get(dev, table, i); - if (err) - goto fail; - } - - return 0; - -fail: - while (i > start) { - i -= inc; - mlx4_table_put(dev, table, i); - } - - return err; -} - -void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end) -{ - u32 i; - - for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) - mlx4_table_put(dev, table, i); -} - -int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u64 virt, int obj_size, u64 nobj, int reserved, - int use_lowmem, int use_coherent) -{ - int obj_per_chunk; - int num_icm; - unsigned chunk_size; - int i; - u64 size; - - obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; - num_icm = div_u64((nobj + obj_per_chunk - 1), obj_per_chunk); - - table->icm = kcalloc(num_icm, sizeof *table->icm, GFP_KERNEL); - if (!table->icm) - return -ENOMEM; - table->virt = virt; - table->num_icm = num_icm; - table->num_obj = nobj; - table->obj_size = obj_size; - table->lowmem = use_lowmem; - table->coherent = use_coherent; - mutex_init(&table->mutex); - - size = (u64) nobj * obj_size; - for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { - chunk_size = MLX4_TABLE_CHUNK_SIZE; - if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > size) - chunk_size = PAGE_ALIGN(size - - i * MLX4_TABLE_CHUNK_SIZE); - - table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, - (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN, use_coherent); - if (!table->icm[i]) - goto err; - if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i], use_coherent); - table->icm[i] = NULL; - goto err; - } - - /* - * Add a reference to this ICM chunk so that it never - * gets freed (since it contains reserved firmware objects). - */ - ++table->icm[i]->refcount; - } - - return 0; - -err: - for (i = 0; i < num_icm; ++i) - if (table->icm[i]) { - if (!mlx4_UNMAP_ICM(dev, - virt + i * MLX4_TABLE_CHUNK_SIZE, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE)) { - mlx4_free_icm(dev, table->icm[i], use_coherent); - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - return -ENOMEM; - } - } - kfree(table->icm); - - return -ENOMEM; -} - -void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) -{ - int i, err = 0; - - for (i = 0; i < table->num_icm; ++i) - if (table->icm[i]) { - err = mlx4_UNMAP_ICM(dev, - table->virt + i * MLX4_TABLE_CHUNK_SIZE, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - if (!err) { - mlx4_free_icm(dev, table->icm[i], - table->coherent); - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - break; - } - } - - if (!err) - kfree(table->icm); -} diff --git a/sys/ofed/drivers/net/mlx4/icm.h b/sys/ofed/drivers/net/mlx4/icm.h deleted file mode 100644 index f7a2537bfbc0..000000000000 --- a/sys/ofed/drivers/net/mlx4/icm.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef MLX4_ICM_H -#define MLX4_ICM_H - -#include <linux/list.h> -#include <linux/pci.h> -#include <linux/mutex.h> -#include <linux/scatterlist.h> - -#define MLX4_ICM_CHUNK_LEN \ - ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ - (sizeof (struct scatterlist))) - -enum { - MLX4_ICM_PAGE_SHIFT = 12, - MLX4_ICM_PAGE_SIZE = 1 << MLX4_ICM_PAGE_SHIFT, -}; - -struct mlx4_icm_chunk { - struct list_head list; - int npages; - int nsg; - struct scatterlist mem[MLX4_ICM_CHUNK_LEN]; -}; - -struct mlx4_icm { - struct list_head chunk_list; - int refcount; -}; - -struct mlx4_icm_iter { - struct mlx4_icm *icm; - struct mlx4_icm_chunk *chunk; - int page_idx; -}; - -struct mlx4_dev; - -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask, int coherent); -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); - -int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); -void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); -int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end); -void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end); -int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u64 virt, int obj_size, u64 nobj, int reserved, - int use_lowmem, int use_coherent); -void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); -void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, dma_addr_t *dma_handle); - -static inline void mlx4_icm_first(struct mlx4_icm *icm, - struct mlx4_icm_iter *iter) -{ - iter->icm = icm; - iter->chunk = list_empty(&icm->chunk_list) ? - NULL : list_entry(icm->chunk_list.next, - struct mlx4_icm_chunk, list); - iter->page_idx = 0; -} - -static inline int mlx4_icm_last(struct mlx4_icm_iter *iter) -{ - return !iter->chunk; -} - -static inline void mlx4_icm_next(struct mlx4_icm_iter *iter) -{ - if (++iter->page_idx >= iter->chunk->nsg) { - if (iter->chunk->list.next == &iter->icm->chunk_list) { - iter->chunk = NULL; - return; - } - - iter->chunk = list_entry(iter->chunk->list.next, - struct mlx4_icm_chunk, list); - iter->page_idx = 0; - } -} - -static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter) -{ - return sg_dma_address(&iter->chunk->mem[iter->page_idx]); -} - -static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter) -{ - return sg_dma_len(&iter->chunk->mem[iter->page_idx]); -} - -int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); -int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev); - -#endif /* MLX4_ICM_H */ diff --git a/sys/ofed/drivers/net/mlx4/intf.c b/sys/ofed/drivers/net/mlx4/intf.c deleted file mode 100644 index 141629801d2f..000000000000 --- a/sys/ofed/drivers/net/mlx4/intf.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/module.h> - -#include "mlx4.h" - -struct mlx4_device_context { - struct list_head list; - struct mlx4_interface *intf; - void *context; -}; - -static LIST_HEAD(intf_list); -static LIST_HEAD(dev_list); -static DEFINE_MUTEX(intf_mutex); - -static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv) -{ - struct mlx4_device_context *dev_ctx; - - dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL); - if (!dev_ctx) - return; - - dev_ctx->intf = intf; - dev_ctx->context = intf->add(&priv->dev); - - if (dev_ctx->context) { - spin_lock_irq(&priv->ctx_lock); - list_add_tail(&dev_ctx->list, &priv->ctx_list); - spin_unlock_irq(&priv->ctx_lock); - } else - kfree(dev_ctx); -} - -static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv) -{ - struct mlx4_device_context *dev_ctx; - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf == intf) { - spin_lock_irq(&priv->ctx_lock); - list_del(&dev_ctx->list); - spin_unlock_irq(&priv->ctx_lock); - - intf->remove(&priv->dev, dev_ctx->context); - kfree(dev_ctx); - return; - } -} - -int mlx4_register_interface(struct mlx4_interface *intf) -{ - struct mlx4_priv *priv; - - if (!intf->add || !intf->remove) - return -EINVAL; - - mutex_lock(&intf_mutex); - - list_add_tail(&intf->list, &intf_list); - list_for_each_entry(priv, &dev_list, dev_list) - mlx4_add_device(intf, priv); - - mutex_unlock(&intf_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_register_interface); - -void mlx4_unregister_interface(struct mlx4_interface *intf) -{ - struct mlx4_priv *priv; - - mutex_lock(&intf_mutex); - - list_for_each_entry(priv, &dev_list, dev_list) - mlx4_remove_device(intf, priv); - - list_del(&intf->list); - - mutex_unlock(&intf_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_unregister_interface); - -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, - unsigned long param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_device_context *dev_ctx; - unsigned long flags; - - spin_lock_irqsave(&priv->ctx_lock, flags); - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf->event) - dev_ctx->intf->event(dev, dev_ctx->context, type, param); - - spin_unlock_irqrestore(&priv->ctx_lock, flags); -} - -int mlx4_register_device(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_interface *intf; - - mutex_lock(&intf_mutex); - - list_add_tail(&priv->dev_list, &dev_list); - list_for_each_entry(intf, &intf_list, list) - mlx4_add_device(intf, priv); - - mutex_unlock(&intf_mutex); - if (!mlx4_is_slave(dev)) - mlx4_start_catas_poll(dev); - - return 0; -} - -void mlx4_unregister_device(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_interface *intf; - - if (!mlx4_is_slave(dev)) - mlx4_stop_catas_poll(dev); - mutex_lock(&intf_mutex); - - list_for_each_entry(intf, &intf_list, list) - mlx4_remove_device(intf, priv); - - list_del_init(&priv->dev_list); - - mutex_unlock(&intf_mutex); -} - -void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_device_context *dev_ctx; - unsigned long flags; - void *result = NULL; - - spin_lock_irqsave(&priv->ctx_lock, flags); - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) { - result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port); - break; - } - - spin_unlock_irqrestore(&priv->ctx_lock, flags); - - return result; -} -EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev); diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c deleted file mode 100644 index 78e8f1bb585e..000000000000 --- a/sys/ofed/drivers/net/mlx4/main.c +++ /dev/null @@ -1,3883 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/kmod.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/io-mapping.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/string.h> -#include <linux/fs.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/doorbell.h> - -#include "mlx4.h" -#include "fw.h" -#include "icm.h" -#include "mlx4_stats.h" - -/* Mellanox ConnectX HCA low-level driver */ - -struct workqueue_struct *mlx4_wq; - -#ifdef CONFIG_MLX4_DEBUG - -int mlx4_debug_level = 0; -module_param_named(debug_level, mlx4_debug_level, int, 0644); -MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); - -#endif /* CONFIG_MLX4_DEBUG */ - -#ifdef CONFIG_PCI_MSI - -static int msi_x = 1; -module_param(msi_x, int, 0444); -MODULE_PARM_DESC(msi_x, "0 - don't use MSI-X, 1 - use MSI-X, >1 - limit number of MSI-X irqs to msi_x (non-SRIOV only)"); - -#else /* CONFIG_PCI_MSI */ - -#define msi_x (0) - -#endif /* CONFIG_PCI_MSI */ - -static int enable_sys_tune = 0; -module_param(enable_sys_tune, int, 0444); -MODULE_PARM_DESC(enable_sys_tune, "Tune the cpu's for better performance (default 0)"); - -int mlx4_blck_lb = 1; -module_param_named(block_loopback, mlx4_blck_lb, int, 0644); -MODULE_PARM_DESC(block_loopback, "Block multicast loopback packets if > 0 " - "(default: 1)"); -enum { - DEFAULT_DOMAIN = 0, - BDF_STR_SIZE = 8, /* bb:dd.f- */ - DBDF_STR_SIZE = 13 /* mmmm:bb:dd.f- */ -}; - -enum { - NUM_VFS, - PROBE_VF, - PORT_TYPE_ARRAY -}; - -enum { - VALID_DATA, - INVALID_DATA, - INVALID_STR -}; - -struct param_data { - int id; - struct mlx4_dbdf2val_lst dbdf2val; -}; - -static struct param_data num_vfs = { - .id = NUM_VFS, - .dbdf2val = { - .name = "num_vfs param", - .num_vals = 1, - .def_val = {0}, - .range = {0, MLX4_MAX_NUM_VF} - } -}; -module_param_string(num_vfs, num_vfs.dbdf2val.str, - sizeof(num_vfs.dbdf2val.str), 0444); -MODULE_PARM_DESC(num_vfs, - "Either single value (e.g. '5') to define uniform num_vfs value for all devices functions\n" - "\t\tor a string to map device function numbers to their num_vfs values (e.g. '0000:04:00.0-5,002b:1c:0b.a-15').\n" - "\t\tHexadecimal digits for the device function (e.g. 002b:1c:0b.a) and decimal for num_vfs value (e.g. 15)."); - -static struct param_data probe_vf = { - .id = PROBE_VF, - .dbdf2val = { - .name = "probe_vf param", - .num_vals = 1, - .def_val = {0}, - .range = {0, MLX4_MAX_NUM_VF} - } -}; -module_param_string(probe_vf, probe_vf.dbdf2val.str, - sizeof(probe_vf.dbdf2val.str), 0444); -MODULE_PARM_DESC(probe_vf, - "Either single value (e.g. '3') to define uniform number of VFs to probe by the pf driver for all devices functions\n" - "\t\tor a string to map device function numbers to their probe_vf values (e.g. '0000:04:00.0-3,002b:1c:0b.a-13').\n" - "\t\tHexadecimal digits for the device function (e.g. 002b:1c:0b.a) and decimal for probe_vf value (e.g. 13)."); - -int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; - -module_param_named(log_num_mgm_entry_size, - mlx4_log_num_mgm_entry_size, int, 0444); -MODULE_PARM_DESC(log_num_mgm_entry_size, "log mgm size, that defines the num" - " of qp per mcg, for example:" - " 10 gives 248.range: 7 <=" - " log_num_mgm_entry_size <= 12." - " To activate device managed" - " flow steering when available, set to -1"); - -static int high_rate_steer; -module_param(high_rate_steer, int, 0444); -MODULE_PARM_DESC(high_rate_steer, "Enable steering mode for higher packet rate" - " (default off)"); - -static int fast_drop; -module_param_named(fast_drop, fast_drop, int, 0444); -MODULE_PARM_DESC(fast_drop, - "Enable fast packet drop when no receive WQEs are posted"); - -int mlx4_enable_64b_cqe_eqe = 1; -module_param_named(enable_64b_cqe_eqe, mlx4_enable_64b_cqe_eqe, int, 0644); -MODULE_PARM_DESC(enable_64b_cqe_eqe, - "Enable 64 byte CQEs/EQEs when the FW supports this if non-zero (default: 1)"); - -#define HCA_GLOBAL_CAP_MASK 0 - -#define PF_CONTEXT_BEHAVIOUR_MASK MLX4_FUNC_CAP_64B_EQE_CQE - -static char mlx4_version[] __devinitdata = - DRV_NAME ": Mellanox ConnectX VPI driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; - -static int log_num_mac = 7; -module_param_named(log_num_mac, log_num_mac, int, 0444); -MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)"); - -static int log_num_vlan; -module_param_named(log_num_vlan, log_num_vlan, int, 0444); -MODULE_PARM_DESC(log_num_vlan, - "(Obsolete) Log2 max number of VLANs per ETH port (0-7)"); -/* Log2 max number of VLANs per ETH port (0-7) */ -#define MLX4_LOG_NUM_VLANS 7 - -int log_mtts_per_seg = ilog2(1); -module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); -MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment " - "(0-7) (default: 0)"); - -static struct param_data port_type_array = { - .id = PORT_TYPE_ARRAY, - .dbdf2val = { - .name = "port_type_array param", - .num_vals = 2, - .def_val = {MLX4_PORT_TYPE_ETH, MLX4_PORT_TYPE_ETH}, - .range = {MLX4_PORT_TYPE_IB, MLX4_PORT_TYPE_NA} - } -}; -module_param_string(port_type_array, port_type_array.dbdf2val.str, - sizeof(port_type_array.dbdf2val.str), 0444); -MODULE_PARM_DESC(port_type_array, - "Either pair of values (e.g. '1,2') to define uniform port1/port2 types configuration for all devices functions\n" - "\t\tor a string to map device function numbers to their pair of port types values (e.g. '0000:04:00.0-1;2,002b:1c:0b.a-1;1').\n" - "\t\tValid port types: 1-ib, 2-eth, 3-auto, 4-N/A\n" - "\t\tIn case that only one port is available use the N/A port type for port2 (e.g '1,4')."); - - -struct mlx4_port_config { - struct list_head list; - enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; - struct pci_dev *pdev; -}; - -#define MLX4_LOG_NUM_MTT 20 -/* We limit to 30 as of a bit map issue which uses int and not uint. - see mlx4_buddy_init -> bitmap_zero which gets int. -*/ -#define MLX4_MAX_LOG_NUM_MTT 30 -static struct mlx4_profile mod_param_profile = { - .num_qp = 19, - .num_srq = 16, - .rdmarc_per_qp = 4, - .num_cq = 16, - .num_mcg = 13, - .num_mpt = 19, - .num_mtt_segs = 0, /* max(20, 2*MTTs for host memory)) */ -}; - -module_param_named(log_num_qp, mod_param_profile.num_qp, int, 0444); -MODULE_PARM_DESC(log_num_qp, "log maximum number of QPs per HCA (default: 19)"); - -module_param_named(log_num_srq, mod_param_profile.num_srq, int, 0444); -MODULE_PARM_DESC(log_num_srq, "log maximum number of SRQs per HCA " - "(default: 16)"); - -module_param_named(log_rdmarc_per_qp, mod_param_profile.rdmarc_per_qp, int, - 0444); -MODULE_PARM_DESC(log_rdmarc_per_qp, "log number of RDMARC buffers per QP " - "(default: 4)"); - -module_param_named(log_num_cq, mod_param_profile.num_cq, int, 0444); -MODULE_PARM_DESC(log_num_cq, "log maximum number of CQs per HCA (default: 16)"); - -module_param_named(log_num_mcg, mod_param_profile.num_mcg, int, 0444); -MODULE_PARM_DESC(log_num_mcg, "log maximum number of multicast groups per HCA " - "(default: 13)"); - -module_param_named(log_num_mpt, mod_param_profile.num_mpt, int, 0444); -MODULE_PARM_DESC(log_num_mpt, - "log maximum number of memory protection table entries per " - "HCA (default: 19)"); - -module_param_named(log_num_mtt, mod_param_profile.num_mtt_segs, int, 0444); -MODULE_PARM_DESC(log_num_mtt, - "log maximum number of memory translation table segments per " - "HCA (default: max(20, 2*MTTs for register all of the host memory limited to 30))"); - -enum { - MLX4_IF_STATE_BASIC, - MLX4_IF_STATE_EXTENDED -}; - -static inline u64 dbdf_to_u64(int domain, int bus, int dev, int fn) -{ - return (domain << 20) | (bus << 12) | (dev << 4) | fn; -} - -static inline void pr_bdf_err(const char *dbdf, const char *pname) -{ - pr_warn("mlx4_core: '%s' is not valid bdf in '%s'\n", dbdf, pname); -} - -static inline void pr_val_err(const char *dbdf, const char *pname, - const char *val) -{ - pr_warn("mlx4_core: value '%s' of bdf '%s' in '%s' is not valid\n" - , val, dbdf, pname); -} - -static inline void pr_out_of_range_bdf(const char *dbdf, int val, - struct mlx4_dbdf2val_lst *dbdf2val) -{ - pr_warn("mlx4_core: value %d in bdf '%s' of '%s' is out of its valid range (%d,%d)\n" - , val, dbdf, dbdf2val->name , dbdf2val->range.min, - dbdf2val->range.max); -} - -static inline void pr_out_of_range(struct mlx4_dbdf2val_lst *dbdf2val) -{ - pr_warn("mlx4_core: value of '%s' is out of its valid range (%d,%d)\n" - , dbdf2val->name , dbdf2val->range.min, dbdf2val->range.max); -} - -static inline int is_in_range(int val, struct mlx4_range *r) -{ - return (val >= r->min && val <= r->max); -} - -static int update_defaults(struct param_data *pdata) -{ - long int val[MLX4_MAX_BDF_VALS]; - int ret; - char *t, *p = pdata->dbdf2val.str; - char sval[32]; - int val_len; - - if (!strlen(p) || strchr(p, ':') || strchr(p, '.') || strchr(p, ';')) - return INVALID_STR; - - switch (pdata->id) { - case PORT_TYPE_ARRAY: - t = strchr(p, ','); - if (!t || t == p || (t - p) > sizeof(sval)) - return INVALID_STR; - - val_len = t - p; - strncpy(sval, p, val_len); - sval[val_len] = 0; - - ret = kstrtol(sval, 0, &val[0]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[0], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - - ret = kstrtol(t + 1, 0, &val[1]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[1], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - - pdata->dbdf2val.tbl[0].val[0] = val[0]; - pdata->dbdf2val.tbl[0].val[1] = val[1]; - break; - - case NUM_VFS: - case PROBE_VF: - ret = kstrtol(p, 0, &val[0]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[0], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - pdata->dbdf2val.tbl[0].val[0] = val[0]; - break; - } - pdata->dbdf2val.tbl[1].dbdf = MLX4_ENDOF_TBL; - - return VALID_DATA; -} - -int mlx4_fill_dbdf2val_tbl(struct mlx4_dbdf2val_lst *dbdf2val_lst) -{ - int domain, bus, dev, fn; - u64 dbdf; - char *p, *t, *v; - char tmp[32]; - char sbdf[32]; - char sep = ','; - int j, k, str_size, i = 1; - int prfx_size; - - p = dbdf2val_lst->str; - - for (j = 0; j < dbdf2val_lst->num_vals; j++) - dbdf2val_lst->tbl[0].val[j] = dbdf2val_lst->def_val[j]; - dbdf2val_lst->tbl[1].dbdf = MLX4_ENDOF_TBL; - - str_size = strlen(dbdf2val_lst->str); - - if (str_size == 0) - return 0; - - while (strlen(p)) { - prfx_size = BDF_STR_SIZE; - sbdf[prfx_size] = 0; - strncpy(sbdf, p, prfx_size); - domain = DEFAULT_DOMAIN; - if (sscanf(sbdf, "%02x:%02x.%x-", &bus, &dev, &fn) != 3) { - prfx_size = DBDF_STR_SIZE; - sbdf[prfx_size] = 0; - strncpy(sbdf, p, prfx_size); - if (sscanf(sbdf, "%04x:%02x:%02x.%x-", &domain, &bus, - &dev, &fn) != 4) { - pr_bdf_err(sbdf, dbdf2val_lst->name); - goto err; - } - sprintf(tmp, "%04x:%02x:%02x.%x-", domain, bus, dev, - fn); - } else { - sprintf(tmp, "%02x:%02x.%x-", bus, dev, fn); - } - - if (strnicmp(sbdf, tmp, sizeof(tmp))) { - pr_bdf_err(sbdf, dbdf2val_lst->name); - goto err; - } - - dbdf = dbdf_to_u64(domain, bus, dev, fn); - - for (j = 1; j < i; j++) - if (dbdf2val_lst->tbl[j].dbdf == dbdf) { - pr_warn("mlx4_core: in '%s', %s appears multiple times\n" - , dbdf2val_lst->name, sbdf); - goto err; - } - - if (i >= MLX4_DEVS_TBL_SIZE) { - pr_warn("mlx4_core: Too many devices in '%s'\n" - , dbdf2val_lst->name); - goto err; - } - - p += prfx_size; - t = strchr(p, sep); - t = t ? t : p + strlen(p); - if (p >= t) { - pr_val_err(sbdf, dbdf2val_lst->name, ""); - goto err; - } - - for (k = 0; k < dbdf2val_lst->num_vals; k++) { - char sval[32]; - long int val; - int ret, val_len; - char vsep = ';'; - - v = (k == dbdf2val_lst->num_vals - 1) ? t : strchr(p, vsep); - if (!v || v > t || v == p || (v - p) > sizeof(sval)) { - pr_val_err(sbdf, dbdf2val_lst->name, p); - goto err; - } - val_len = v - p; - strncpy(sval, p, val_len); - sval[val_len] = 0; - - ret = kstrtol(sval, 0, &val); - if (ret) { - if (strchr(p, vsep)) - pr_warn("mlx4_core: too many vals in bdf '%s' of '%s'\n" - , sbdf, dbdf2val_lst->name); - else - pr_val_err(sbdf, dbdf2val_lst->name, - sval); - goto err; - } - if (!is_in_range(val, &dbdf2val_lst->range)) { - pr_out_of_range_bdf(sbdf, val, dbdf2val_lst); - goto err; - } - - dbdf2val_lst->tbl[i].val[k] = val; - p = v; - if (p[0] == vsep) - p++; - } - - dbdf2val_lst->tbl[i].dbdf = dbdf; - if (strlen(p)) { - if (p[0] != sep) { - pr_warn("mlx4_core: expect separator '%c' before '%s' in '%s'\n" - , sep, p, dbdf2val_lst->name); - goto err; - } - p++; - } - i++; - if (i < MLX4_DEVS_TBL_SIZE) - dbdf2val_lst->tbl[i].dbdf = MLX4_ENDOF_TBL; - } - - return 0; - -err: - dbdf2val_lst->tbl[1].dbdf = MLX4_ENDOF_TBL; - pr_warn("mlx4_core: The value of '%s' is incorrect. The value is discarded!\n" - , dbdf2val_lst->name); - - return -EINVAL; -} -EXPORT_SYMBOL(mlx4_fill_dbdf2val_tbl); - -int mlx4_get_val(struct mlx4_dbdf2val *tbl, struct pci_dev *pdev, int idx, - int *val) -{ - u64 dbdf; - int i = 1; - - *val = tbl[0].val[idx]; - if (!pdev) - return -EINVAL; - - dbdf = dbdf_to_u64(pci_get_domain(pdev->dev.bsddev), pci_get_bus(pdev->dev.bsddev), - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - while ((i < MLX4_DEVS_TBL_SIZE) && (tbl[i].dbdf != MLX4_ENDOF_TBL)) { - if (tbl[i].dbdf == dbdf) { - *val = tbl[i].val[idx]; - return 0; - } - i++; - } - - return 0; -} -EXPORT_SYMBOL(mlx4_get_val); - -static void process_mod_param_profile(struct mlx4_profile *profile) -{ - vm_size_t hwphyssz; - hwphyssz = 0; - TUNABLE_ULONG_FETCH("hw.realmem", (u_long *) &hwphyssz); - - profile->num_qp = 1 << mod_param_profile.num_qp; - profile->num_srq = 1 << mod_param_profile.num_srq; - profile->rdmarc_per_qp = 1 << mod_param_profile.rdmarc_per_qp; - profile->num_cq = 1 << mod_param_profile.num_cq; - profile->num_mcg = 1 << mod_param_profile.num_mcg; - profile->num_mpt = 1 << mod_param_profile.num_mpt; - /* - * We want to scale the number of MTTs with the size of the - * system memory, since it makes sense to register a lot of - * memory on a system with a lot of memory. As a heuristic, - * make sure we have enough MTTs to register twice the system - * memory (with PAGE_SIZE entries). - * - * This number has to be a power of two and fit into 32 bits - * due to device limitations. We cap this at 2^30 as of bit map - * limitation to work with int instead of uint (mlx4_buddy_init -> bitmap_zero) - * That limits us to 4TB of memory registration per HCA with - * 4KB pages, which is probably OK for the next few months. - */ - if (mod_param_profile.num_mtt_segs) - profile->num_mtt_segs = 1 << mod_param_profile.num_mtt_segs; - else { - profile->num_mtt_segs = - roundup_pow_of_two(max_t(unsigned, - 1 << (MLX4_LOG_NUM_MTT - log_mtts_per_seg), - min(1UL << - (MLX4_MAX_LOG_NUM_MTT - - log_mtts_per_seg), - (hwphyssz << 1) - >> log_mtts_per_seg))); - /* set the actual value, so it will be reflected to the user - using the sysfs */ - mod_param_profile.num_mtt_segs = ilog2(profile->num_mtt_segs); - } -} - -int mlx4_check_port_params(struct mlx4_dev *dev, - enum mlx4_port_type *port_type) -{ - int i; - - for (i = 0; i < dev->caps.num_ports - 1; i++) { - if (port_type[i] != port_type[i + 1]) { - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { - mlx4_err(dev, "Only same port types supported " - "on this HCA, aborting.\n"); - return -EINVAL; - } - } - } - - for (i = 0; i < dev->caps.num_ports; i++) { - if (!(port_type[i] & dev->caps.supported_type[i+1])) { - mlx4_err(dev, "Requested port type for port %d is not " - "supported on this HCA\n", i + 1); - return -EINVAL; - } - } - return 0; -} - -static void mlx4_set_port_mask(struct mlx4_dev *dev) -{ - int i; - - for (i = 1; i <= dev->caps.num_ports; ++i) - dev->caps.port_mask[i] = dev->caps.port_type[i]; -} - -static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) -{ - int err; - int i; - - err = mlx4_QUERY_DEV_CAP(dev, dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - return err; - } - - if (dev_cap->min_page_sz > PAGE_SIZE) { - mlx4_err(dev, "HCA minimum page size of %d bigger than " - "kernel PAGE_SIZE of %d, aborting.\n", - dev_cap->min_page_sz, (int)PAGE_SIZE); - return -ENODEV; - } - if (dev_cap->num_ports > MLX4_MAX_PORTS) { - mlx4_err(dev, "HCA has %d ports, but we only support %d, " - "aborting.\n", - dev_cap->num_ports, MLX4_MAX_PORTS); - return -ENODEV; - } - - if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) { - mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than " - "PCI resource 2 size of 0x%llx, aborting.\n", - dev_cap->uar_size, - (unsigned long long) pci_resource_len(dev->pdev, 2)); - return -ENODEV; - } - - dev->caps.num_ports = dev_cap->num_ports; - dev->phys_caps.num_phys_eqs = MLX4_MAX_EQ_NUM; - for (i = 1; i <= dev->caps.num_ports; ++i) { - dev->caps.vl_cap[i] = dev_cap->max_vl[i]; - dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i]; - dev->phys_caps.gid_phys_table_len[i] = dev_cap->max_gids[i]; - dev->phys_caps.pkey_phys_table_len[i] = dev_cap->max_pkeys[i]; - /* set gid and pkey table operating lengths by default - * to non-sriov values */ - dev->caps.gid_table_len[i] = dev_cap->max_gids[i]; - dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i]; - dev->caps.port_width_cap[i] = dev_cap->max_port_width[i]; - dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; - dev->caps.def_mac[i] = dev_cap->def_mac[i]; - dev->caps.supported_type[i] = dev_cap->supported_port_types[i]; - dev->caps.suggested_type[i] = dev_cap->suggested_type[i]; - dev->caps.default_sense[i] = dev_cap->default_sense[i]; - dev->caps.trans_type[i] = dev_cap->trans_type[i]; - dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i]; - dev->caps.wavelength[i] = dev_cap->wavelength[i]; - dev->caps.trans_code[i] = dev_cap->trans_code[i]; - } - - dev->caps.uar_page_size = PAGE_SIZE; - dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; - dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay; - dev->caps.bf_reg_size = dev_cap->bf_reg_size; - dev->caps.bf_regs_per_page = dev_cap->bf_regs_per_page; - dev->caps.max_sq_sg = dev_cap->max_sq_sg; - dev->caps.max_rq_sg = dev_cap->max_rq_sg; - dev->caps.max_wqes = dev_cap->max_qp_sz; - dev->caps.max_qp_init_rdma = dev_cap->max_requester_per_qp; - dev->caps.max_srq_wqes = dev_cap->max_srq_sz; - dev->caps.max_srq_sge = dev_cap->max_rq_sg - 1; - dev->caps.reserved_srqs = dev_cap->reserved_srqs; - dev->caps.max_sq_desc_sz = dev_cap->max_sq_desc_sz; - dev->caps.max_rq_desc_sz = dev_cap->max_rq_desc_sz; - /* - * Subtract 1 from the limit because we need to allocate a - * spare CQE to enable resizing the CQ - */ - dev->caps.max_cqes = dev_cap->max_cq_sz - 1; - dev->caps.reserved_cqs = dev_cap->reserved_cqs; - dev->caps.reserved_eqs = dev_cap->reserved_eqs; - dev->caps.reserved_mtts = dev_cap->reserved_mtts; - dev->caps.reserved_mrws = dev_cap->reserved_mrws; - - /* The first 128 UARs are used for EQ doorbells */ - dev->caps.reserved_uars = max_t(int, 128, dev_cap->reserved_uars); - dev->caps.reserved_pds = dev_cap->reserved_pds; - dev->caps.reserved_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? - dev_cap->reserved_xrcds : 0; - dev->caps.max_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? - dev_cap->max_xrcds : 0; - dev->caps.mtt_entry_sz = dev_cap->mtt_entry_sz; - - dev->caps.max_msg_sz = dev_cap->max_msg_sz; - dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); - dev->caps.flags = dev_cap->flags; - dev->caps.flags2 = dev_cap->flags2; - dev->caps.bmme_flags = dev_cap->bmme_flags; - dev->caps.reserved_lkey = dev_cap->reserved_lkey; - dev->caps.stat_rate_support = dev_cap->stat_rate_support; - dev->caps.cq_timestamp = dev_cap->timestamp_support; - dev->caps.max_gso_sz = dev_cap->max_gso_sz; - dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz; - - /* Sense port always allowed on supported devices for ConnectX-1 and -2 */ - if (mlx4_priv(dev)->pci_dev_data & MLX4_PCI_DEV_FORCE_SENSE_PORT) - dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; - /* Don't do sense port on multifunction devices (for now at least) */ - if (mlx4_is_mfunc(dev)) - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; - - dev->caps.log_num_macs = log_num_mac; - dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS; - - dev->caps.fast_drop = fast_drop ? - !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_FAST_DROP) : - 0; - - for (i = 1; i <= dev->caps.num_ports; ++i) { - dev->caps.port_type[i] = MLX4_PORT_TYPE_NONE; - if (dev->caps.supported_type[i]) { - /* if only ETH is supported - assign ETH */ - if (dev->caps.supported_type[i] == MLX4_PORT_TYPE_ETH) - dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH; - /* if only IB is supported, assign IB */ - else if (dev->caps.supported_type[i] == - MLX4_PORT_TYPE_IB) - dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; - else { - /* - * if IB and ETH are supported, we set the port - * type according to user selection of port type; - * if there is no user selection, take the FW hint - */ - int pta; - mlx4_get_val(port_type_array.dbdf2val.tbl, - pci_physfn(dev->pdev), i - 1, - &pta); - if (pta == MLX4_PORT_TYPE_NONE) { - dev->caps.port_type[i] = dev->caps.suggested_type[i] ? - MLX4_PORT_TYPE_ETH : MLX4_PORT_TYPE_IB; - } else if (pta == MLX4_PORT_TYPE_NA) { - mlx4_err(dev, "Port %d is valid port. " - "It is not allowed to configure its type to N/A(%d)\n", - i, MLX4_PORT_TYPE_NA); - return -EINVAL; - } else { - dev->caps.port_type[i] = pta; - } - } - } - /* - * Link sensing is allowed on the port if 3 conditions are true: - * 1. Both protocols are supported on the port. - * 2. Different types are supported on the port - * 3. FW declared that it supports link sensing - */ - mlx4_priv(dev)->sense.sense_allowed[i] = - ((dev->caps.supported_type[i] == MLX4_PORT_TYPE_AUTO) && - (dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP) && - (dev->caps.flags & MLX4_DEV_CAP_FLAG_SENSE_SUPPORT)); - - /* Disablling auto sense for default Eth ports support */ - mlx4_priv(dev)->sense.sense_allowed[i] = 0; - - /* - * If "default_sense" bit is set, we move the port to "AUTO" mode - * and perform sense_port FW command to try and set the correct - * port type from beginning - */ - if (mlx4_priv(dev)->sense.sense_allowed[i] && dev->caps.default_sense[i]) { - enum mlx4_port_type sensed_port = MLX4_PORT_TYPE_NONE; - dev->caps.possible_type[i] = MLX4_PORT_TYPE_AUTO; - mlx4_SENSE_PORT(dev, i, &sensed_port); - if (sensed_port != MLX4_PORT_TYPE_NONE) - dev->caps.port_type[i] = sensed_port; - } else { - dev->caps.possible_type[i] = dev->caps.port_type[i]; - } - - if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { - dev->caps.log_num_macs = dev_cap->log_max_macs[i]; - mlx4_warn(dev, "Requested number of MACs is too much " - "for port %d, reducing to %d.\n", - i, 1 << dev->caps.log_num_macs); - } - if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) { - dev->caps.log_num_vlans = dev_cap->log_max_vlans[i]; - mlx4_warn(dev, "Requested number of VLANs is too much " - "for port %d, reducing to %d.\n", - i, 1 << dev->caps.log_num_vlans); - } - } - - dev->caps.max_basic_counters = dev_cap->max_basic_counters; - dev->caps.max_extended_counters = dev_cap->max_extended_counters; - /* support extended counters if available */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS_EXT) - dev->caps.max_counters = dev->caps.max_extended_counters; - else - dev->caps.max_counters = dev->caps.max_basic_counters; - - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps; - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = - (1 << dev->caps.log_num_macs) * - (1 << dev->caps.log_num_vlans) * - dev->caps.num_ports; - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH; - - dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH]; - - dev->caps.sync_qp = dev_cap->sync_qp; - if (dev->pdev->device == 0x1003) - dev->caps.cq_flags |= MLX4_DEV_CAP_CQ_FLAG_IO; - - dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0; - - if (!mlx4_enable_64b_cqe_eqe && !mlx4_is_slave(dev)) { - if (dev_cap->flags & - (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) { - mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n"); - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_64B_CQE; - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_64B_EQE; - } - } - - if ((dev->caps.flags & - (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) && - mlx4_is_master(dev)) - dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE; - - if (!mlx4_is_slave(dev)) { - for (i = 0; i < dev->caps.num_ports; ++i) - dev->caps.def_counter_index[i] = i << 1; - } - - return 0; -} -/*The function checks if there are live vf, return the num of them*/ -static int mlx4_how_many_lives_vf(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state; - int i; - int ret = 0; - - for (i = 1/*the ppf is 0*/; i < dev->num_slaves; ++i) { - s_state = &priv->mfunc.master.slave_state[i]; - if (s_state->active && s_state->last_cmd != - MLX4_COMM_CMD_RESET) { - mlx4_warn(dev, "%s: slave: %d is still active\n", - __func__, i); - ret++; - } - } - return ret; -} - -int mlx4_get_parav_qkey(struct mlx4_dev *dev, u32 qpn, u32 *qkey) -{ - u32 qk = MLX4_RESERVED_QKEY_BASE; - - if (qpn >= dev->phys_caps.base_tunnel_sqpn + 8 * MLX4_MFUNC_MAX || - qpn < dev->phys_caps.base_proxy_sqpn) - return -EINVAL; - - if (qpn >= dev->phys_caps.base_tunnel_sqpn) - /* tunnel qp */ - qk += qpn - dev->phys_caps.base_tunnel_sqpn; - else - qk += qpn - dev->phys_caps.base_proxy_sqpn; - *qkey = qk; - return 0; -} -EXPORT_SYMBOL(mlx4_get_parav_qkey); - -void mlx4_sync_pkey_table(struct mlx4_dev *dev, int slave, int port, int i, int val) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return; - - priv->virt2phys_pkey[slave][port - 1][i] = val; -} -EXPORT_SYMBOL(mlx4_sync_pkey_table); - -void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return; - - priv->slave_node_guids[slave] = guid; -} -EXPORT_SYMBOL(mlx4_put_slave_node_guid); - -__be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return 0; - - return priv->slave_node_guids[slave]; -} -EXPORT_SYMBOL(mlx4_get_slave_node_guid); - -int mlx4_is_slave_active(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_slave; - - if (!mlx4_is_master(dev)) - return 0; - - s_slave = &priv->mfunc.master.slave_state[slave]; - return !!s_slave->active; -} -EXPORT_SYMBOL(mlx4_is_slave_active); - -static void slave_adjust_steering_mode(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *hca_param) -{ - dev->caps.steering_mode = hca_param->steering_mode; - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) - dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry; - else - dev->caps.num_qp_per_mgm = - 4 * ((1 << hca_param->log_mc_entry_sz)/16 - 2); - - mlx4_dbg(dev, "Steering mode is: %s\n", - mlx4_steering_mode_str(dev->caps.steering_mode)); -} - -static int mlx4_slave_cap(struct mlx4_dev *dev) -{ - int err; - u32 page_size; - struct mlx4_dev_cap dev_cap; - struct mlx4_func_cap func_cap; - struct mlx4_init_hca_param hca_param; - int i; - - memset(&hca_param, 0, sizeof(hca_param)); - err = mlx4_QUERY_HCA(dev, &hca_param); - if (err) { - mlx4_err(dev, "QUERY_HCA command failed, aborting.\n"); - return err; - } - - /*fail if the hca has an unknown capability */ - if ((hca_param.global_caps | HCA_GLOBAL_CAP_MASK) != - HCA_GLOBAL_CAP_MASK) { - mlx4_err(dev, "Unknown hca global capabilities\n"); - return -ENOSYS; - } - - mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz; - - dev->caps.hca_core_clock = hca_param.hca_core_clock; - - memset(&dev_cap, 0, sizeof(dev_cap)); - dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp; - err = mlx4_dev_cap(dev, &dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - return err; - } - - err = mlx4_QUERY_FW(dev); - if (err) - mlx4_err(dev, "QUERY_FW command failed: could not get FW version.\n"); - - if (!hca_param.mw_enable) { - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW; - dev->caps.bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN; - } - - page_size = ~dev->caps.page_size_cap + 1; - mlx4_warn(dev, "HCA minimum page size:%d\n", page_size); - if (page_size > PAGE_SIZE) { - mlx4_err(dev, "HCA minimum page size of %d bigger than " - "kernel PAGE_SIZE of %d, aborting.\n", - page_size, (int)PAGE_SIZE); - return -ENODEV; - } - - /* slave gets uar page size from QUERY_HCA fw command */ - dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12); - - /* TODO: relax this assumption */ - if (dev->caps.uar_page_size != PAGE_SIZE) { - mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %d\n", - dev->caps.uar_page_size, (int)PAGE_SIZE); - return -ENODEV; - } - - memset(&func_cap, 0, sizeof(func_cap)); - err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap); - if (err) { - mlx4_err(dev, "QUERY_FUNC_CAP general command failed, aborting (%d).\n", - err); - return err; - } - - if ((func_cap.pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) != - PF_CONTEXT_BEHAVIOUR_MASK) { - mlx4_err(dev, "Unknown pf context behaviour\n"); - return -ENOSYS; - } - - dev->caps.num_ports = func_cap.num_ports; - dev->quotas.qp = func_cap.qp_quota; - dev->quotas.srq = func_cap.srq_quota; - dev->quotas.cq = func_cap.cq_quota; - dev->quotas.mpt = func_cap.mpt_quota; - dev->quotas.mtt = func_cap.mtt_quota; - dev->caps.num_qps = 1 << hca_param.log_num_qps; - dev->caps.num_srqs = 1 << hca_param.log_num_srqs; - dev->caps.num_cqs = 1 << hca_param.log_num_cqs; - dev->caps.num_mpts = 1 << hca_param.log_mpt_sz; - dev->caps.num_eqs = func_cap.max_eq; - dev->caps.reserved_eqs = func_cap.reserved_eq; - dev->caps.num_pds = MLX4_NUM_PDS; - dev->caps.num_mgms = 0; - dev->caps.num_amgms = 0; - - if (dev->caps.num_ports > MLX4_MAX_PORTS) { - mlx4_err(dev, "HCA has %d ports, but we only support %d, " - "aborting.\n", dev->caps.num_ports, MLX4_MAX_PORTS); - return -ENODEV; - } - - dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - - if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy || - !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) { - err = -ENOMEM; - goto err_mem; - } - - for (i = 1; i <= dev->caps.num_ports; ++i) { - err = mlx4_QUERY_FUNC_CAP(dev, (u32) i, &func_cap); - if (err) { - mlx4_err(dev, "QUERY_FUNC_CAP port command failed for" - " port %d, aborting (%d).\n", i, err); - goto err_mem; - } - dev->caps.qp0_tunnel[i - 1] = func_cap.qp0_tunnel_qpn; - dev->caps.qp0_proxy[i - 1] = func_cap.qp0_proxy_qpn; - dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn; - dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn; - dev->caps.def_counter_index[i - 1] = func_cap.def_counter_index; - - dev->caps.port_mask[i] = dev->caps.port_type[i]; - err = mlx4_get_slave_pkey_gid_tbl_len(dev, i, - &dev->caps.gid_table_len[i], - &dev->caps.pkey_table_len[i]); - if (err) - goto err_mem; - } - - if (dev->caps.uar_page_size * (dev->caps.num_uars - - dev->caps.reserved_uars) > - pci_resource_len(dev->pdev, 2)) { - mlx4_err(dev, "HCA reported UAR region size of 0x%x bigger than " - "PCI resource 2 size of 0x%llx, aborting.\n", - dev->caps.uar_page_size * dev->caps.num_uars, - (unsigned long long) pci_resource_len(dev->pdev, 2)); - err = -ENOMEM; - goto err_mem; - } - - if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_EQE_ENABLED) { - dev->caps.eqe_size = 64; - dev->caps.eqe_factor = 1; - } else { - dev->caps.eqe_size = 32; - dev->caps.eqe_factor = 0; - } - - if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_CQE_ENABLED) { - dev->caps.cqe_size = 64; - dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_64B_CQE; - } else { - dev->caps.cqe_size = 32; - } - - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_warn(dev, "Timestamping is not supported in slave mode.\n"); - - slave_adjust_steering_mode(dev, &dev_cap, &hca_param); - - return 0; - -err_mem: - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - dev->caps.qp0_tunnel = dev->caps.qp0_proxy = - dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL; - - return err; -} - -static void mlx4_request_modules(struct mlx4_dev *dev) -{ - int port; - int has_ib_port = false; - int has_eth_port = false; -#define EN_DRV_NAME "mlx4_en" -#define IB_DRV_NAME "mlx4_ib" - - for (port = 1; port <= dev->caps.num_ports; port++) { - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB) - has_ib_port = true; - else if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - has_eth_port = true; - } - - if (has_ib_port) - request_module_nowait(IB_DRV_NAME); - if (has_eth_port) - request_module_nowait(EN_DRV_NAME); -} - -/* - * Change the port configuration of the device. - * Every user of this function must hold the port mutex. - */ -int mlx4_change_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *port_types) -{ - int err = 0; - int change = 0; - int port; - - for (port = 0; port < dev->caps.num_ports; port++) { - /* Change the port type only if the new type is different - * from the current, and not set to Auto */ - if (port_types[port] != dev->caps.port_type[port + 1]) - change = 1; - } - if (change) { - mlx4_unregister_device(dev); - for (port = 1; port <= dev->caps.num_ports; port++) { - mlx4_CLOSE_PORT(dev, port); - dev->caps.port_type[port] = port_types[port - 1]; - err = mlx4_SET_PORT(dev, port, -1); - if (err) { - mlx4_err(dev, "Failed to set port %d, " - "aborting\n", port); - goto out; - } - } - mlx4_set_port_mask(dev); - err = mlx4_register_device(dev); - if (err) { - mlx4_err(dev, "Failed to register device\n"); - goto out; - } - mlx4_request_modules(dev); - } - -out: - return err; -} - -static ssize_t show_port_type(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_attr); - struct mlx4_dev *mdev = info->dev; - char type[8]; - - sprintf(type, "%s", - (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB) ? - "ib" : "eth"); - if (mdev->caps.possible_type[info->port] == MLX4_PORT_TYPE_AUTO) - sprintf(buf, "auto (%s)\n", type); - else - sprintf(buf, "%s\n", type); - - return strlen(buf); -} - -static ssize_t set_port_type(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_attr); - struct mlx4_dev *mdev = info->dev; - struct mlx4_priv *priv = mlx4_priv(mdev); - enum mlx4_port_type types[MLX4_MAX_PORTS]; - enum mlx4_port_type new_types[MLX4_MAX_PORTS]; - int i; - int err = 0; - - if (!strcmp(buf, "ib\n")) - info->tmp_type = MLX4_PORT_TYPE_IB; - else if (!strcmp(buf, "eth\n")) - info->tmp_type = MLX4_PORT_TYPE_ETH; - else if (!strcmp(buf, "auto\n")) - info->tmp_type = MLX4_PORT_TYPE_AUTO; - else { - mlx4_err(mdev, "%s is not supported port type\n", buf); - return -EINVAL; - } - - if ((info->tmp_type & mdev->caps.supported_type[info->port]) != - info->tmp_type) { - mlx4_err(mdev, "Requested port type for port %d is not supported on this HCA\n", - info->port); - return -EINVAL; - } - - mlx4_stop_sense(mdev); - mutex_lock(&priv->port_mutex); - /* Possible type is always the one that was delivered */ - mdev->caps.possible_type[info->port] = info->tmp_type; - - for (i = 0; i < mdev->caps.num_ports; i++) { - types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type : - mdev->caps.possible_type[i+1]; - if (types[i] == MLX4_PORT_TYPE_AUTO) - types[i] = mdev->caps.port_type[i+1]; - } - - if (!(mdev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP) && - !(mdev->caps.flags & MLX4_DEV_CAP_FLAG_SENSE_SUPPORT)) { - for (i = 1; i <= mdev->caps.num_ports; i++) { - if (mdev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { - mdev->caps.possible_type[i] = mdev->caps.port_type[i]; - err = -EINVAL; - } - } - } - if (err) { - mlx4_err(mdev, "Auto sensing is not supported on this HCA. " - "Set only 'eth' or 'ib' for both ports " - "(should be the same)\n"); - goto out; - } - - mlx4_do_sense_ports(mdev, new_types, types); - - err = mlx4_check_port_params(mdev, new_types); - if (err) - goto out; - - /* We are about to apply the changes after the configuration - * was verified, no need to remember the temporary types - * any more */ - for (i = 0; i < mdev->caps.num_ports; i++) - priv->port[i + 1].tmp_type = 0; - - err = mlx4_change_port_types(mdev, new_types); - -out: - mlx4_start_sense(mdev); - mutex_unlock(&priv->port_mutex); - return err ? err : count; -} - -enum ibta_mtu { - IB_MTU_256 = 1, - IB_MTU_512 = 2, - IB_MTU_1024 = 3, - IB_MTU_2048 = 4, - IB_MTU_4096 = 5 -}; - -static inline int int_to_ibta_mtu(int mtu) -{ - switch (mtu) { - case 256: return IB_MTU_256; - case 512: return IB_MTU_512; - case 1024: return IB_MTU_1024; - case 2048: return IB_MTU_2048; - case 4096: return IB_MTU_4096; - default: return -1; - } -} - -static inline int ibta_mtu_to_int(enum ibta_mtu mtu) -{ - switch (mtu) { - case IB_MTU_256: return 256; - case IB_MTU_512: return 512; - case IB_MTU_1024: return 1024; - case IB_MTU_2048: return 2048; - case IB_MTU_4096: return 4096; - default: return -1; - } -} - -static ssize_t -show_board(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - board_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, - mdev->board_id); -} - -static ssize_t -show_hca(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - hca_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "MT%d\n", mdev->pdev->device); -} - -static ssize_t -show_firmware_version(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - firmware_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "%d.%d.%d\n", (int)(mdev->caps.fw_ver >> 32), - (int)(mdev->caps.fw_ver >> 16) & 0xffff, - (int)mdev->caps.fw_ver & 0xffff); -} - -static ssize_t show_port_ib_mtu(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_mtu_attr); - struct mlx4_dev *mdev = info->dev; - - /* When port type is eth, port mtu value isn't used. */ - if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) - return -EINVAL; - - sprintf(buf, "%d\n", - ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port])); - return strlen(buf); -} - -static ssize_t set_port_ib_mtu(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_mtu_attr); - struct mlx4_dev *mdev = info->dev; - struct mlx4_priv *priv = mlx4_priv(mdev); - int err, port, mtu, ibta_mtu = -1; - - if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) { - mlx4_warn(mdev, "port level mtu is only used for IB ports\n"); - return -EINVAL; - } - - mtu = (int) simple_strtol(buf, NULL, 0); - ibta_mtu = int_to_ibta_mtu(mtu); - - if (ibta_mtu < 0) { - mlx4_err(mdev, "%s is invalid IBTA mtu\n", buf); - return -EINVAL; - } - - mdev->caps.port_ib_mtu[info->port] = ibta_mtu; - - mlx4_stop_sense(mdev); - mutex_lock(&priv->port_mutex); - mlx4_unregister_device(mdev); - for (port = 1; port <= mdev->caps.num_ports; port++) { - mlx4_CLOSE_PORT(mdev, port); - err = mlx4_SET_PORT(mdev, port, -1); - if (err) { - mlx4_err(mdev, "Failed to set port %d, " - "aborting\n", port); - goto err_set_port; - } - } - err = mlx4_register_device(mdev); -err_set_port: - mutex_unlock(&priv->port_mutex); - mlx4_start_sense(mdev); - return err ? err : count; -} - -static int mlx4_load_fw(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err, unmap_flag = 0; - - priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, - GFP_HIGHUSER | __GFP_NOWARN, 0); - if (!priv->fw.fw_icm) { - mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); - return -ENOMEM; - } - - err = mlx4_MAP_FA(dev, priv->fw.fw_icm); - if (err) { - mlx4_err(dev, "MAP_FA command failed, aborting.\n"); - goto err_free; - } - - err = mlx4_RUN_FW(dev); - if (err) { - mlx4_err(dev, "RUN_FW command failed, aborting.\n"); - goto err_unmap_fa; - } - - return 0; - -err_unmap_fa: - unmap_flag = mlx4_UNMAP_FA(dev); - if (unmap_flag) - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - -err_free: - if (!unmap_flag) - mlx4_free_icm(dev, priv->fw.fw_icm, 0); - return err; -} - -static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, - int cmpt_entry_sz) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int num_eqs; - - err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_QP * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) - goto err; - - err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_SRQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0, 0); - if (err) - goto err_qp; - - err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_CQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0, 0); - if (err) - goto err_srq; - - num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs : - dev->caps.num_eqs; - err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_EQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, num_eqs, num_eqs, 0, 0); - if (err) - goto err_cq; - - return 0; - -err_cq: - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - -err_srq: - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - -err_qp: - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - -err: - return err; -} - -static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca, u64 icm_size) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 aux_pages; - int num_eqs; - int err, unmap_flag = 0; - - err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages); - if (err) { - mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n"); - return err; - } - - mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n", - (unsigned long long) icm_size >> 10, - (unsigned long long) aux_pages << 2); - - priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages, - GFP_HIGHUSER | __GFP_NOWARN, 0); - if (!priv->fw.aux_icm) { - mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); - return -ENOMEM; - } - - err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm); - if (err) { - mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n"); - goto err_free_aux; - } - - err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz); - if (err) { - mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n"); - goto err_unmap_aux; - } - - - num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs : - dev->caps.num_eqs; - err = mlx4_init_icm_table(dev, &priv->eq_table.table, - init_hca->eqc_base, dev_cap->eqc_entry_sz, - num_eqs, num_eqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); - goto err_unmap_cmpt; - } - - /* - * Reserved MTT entries must be aligned up to a cacheline - * boundary, since the FW will write to them, while the driver - * writes to all other MTT entries. (The variable - * dev->caps.mtt_entry_sz below is really the MTT segment - * size, not the raw entry size) - */ - dev->caps.reserved_mtts = - ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, - dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; - - err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, - init_hca->mtt_base, - dev->caps.mtt_entry_sz, - dev->caps.num_mtts, - dev->caps.reserved_mtts, 1, 0); - if (err) { - mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); - goto err_unmap_eq; - } - - err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table, - init_hca->dmpt_base, - dev_cap->dmpt_entry_sz, - dev->caps.num_mpts, - dev->caps.reserved_mrws, 1, 1); - if (err) { - mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); - goto err_unmap_mtt; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table, - init_hca->qpc_base, - dev_cap->qpc_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); - goto err_unmap_dmpt; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table, - init_hca->auxc_base, - dev_cap->aux_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); - goto err_unmap_qp; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table, - init_hca->altc_base, - dev_cap->altc_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); - goto err_unmap_auxc; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table, - init_hca->rdmarc_base, - dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); - goto err_unmap_altc; - } - - err = mlx4_init_icm_table(dev, &priv->cq_table.table, - init_hca->cqc_base, - dev_cap->cqc_entry_sz, - dev->caps.num_cqs, - dev->caps.reserved_cqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); - goto err_unmap_rdmarc; - } - - err = mlx4_init_icm_table(dev, &priv->srq_table.table, - init_hca->srqc_base, - dev_cap->srq_entry_sz, - dev->caps.num_srqs, - dev->caps.reserved_srqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); - goto err_unmap_cq; - } - - /* - * For flow steering device managed mode it is required to use - * mlx4_init_icm_table. For B0 steering mode it's not strictly - * required, but for simplicity just map the whole multicast - * group table now. The table isn't very big and it's a lot - * easier than trying to track ref counts. - */ - err = mlx4_init_icm_table(dev, &priv->mcg_table.table, - init_hca->mc_base, - mlx4_get_mgm_entry_size(dev), - dev->caps.num_mgms + dev->caps.num_amgms, - dev->caps.num_mgms + dev->caps.num_amgms, - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); - goto err_unmap_srq; - } - - return 0; - -err_unmap_srq: - mlx4_cleanup_icm_table(dev, &priv->srq_table.table); - -err_unmap_cq: - mlx4_cleanup_icm_table(dev, &priv->cq_table.table); - -err_unmap_rdmarc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); - -err_unmap_altc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); - -err_unmap_auxc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); - -err_unmap_qp: - mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); - -err_unmap_dmpt: - mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); - -err_unmap_mtt: - mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); - -err_unmap_eq: - mlx4_cleanup_icm_table(dev, &priv->eq_table.table); - -err_unmap_cmpt: - mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - -err_unmap_aux: - unmap_flag = mlx4_UNMAP_ICM_AUX(dev); - if (unmap_flag) - pr_warn("mlx4_core: mlx4_UNMAP_ICM_AUX failed.\n"); - -err_free_aux: - if (!unmap_flag) - mlx4_free_icm(dev, priv->fw.aux_icm, 0); - - return err; -} - -static void mlx4_free_icms(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_cleanup_icm_table(dev, &priv->mcg_table.table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); - mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); - mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); - mlx4_cleanup_icm_table(dev, &priv->eq_table.table); - mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - - if (!mlx4_UNMAP_ICM_AUX(dev)) - mlx4_free_icm(dev, priv->fw.aux_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_ICM_AUX failed.\n"); -} - -static void mlx4_slave_exit(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) - mlx4_warn(dev, "Failed to close slave function.\n"); - mutex_unlock(&priv->cmd.slave_cmd_mutex); -} - -static int map_bf_area(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - resource_size_t bf_start; - resource_size_t bf_len; - int err = 0; - - if (!dev->caps.bf_reg_size) - return -ENXIO; - - bf_start = pci_resource_start(dev->pdev, 2) + - (dev->caps.num_uars << PAGE_SHIFT); - bf_len = pci_resource_len(dev->pdev, 2) - - (dev->caps.num_uars << PAGE_SHIFT); - priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); - if (!priv->bf_mapping) - err = -ENOMEM; - - return err; -} - -static void unmap_bf_area(struct mlx4_dev *dev) -{ - if (mlx4_priv(dev)->bf_mapping) - io_mapping_free(mlx4_priv(dev)->bf_mapping); -} - -int mlx4_read_clock(struct mlx4_dev *dev) -{ - u32 clockhi, clocklo, clockhi1; - cycle_t cycles; - int i; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (!priv->clock_mapping) - return -ENOTSUPP; - - for (i = 0; i < 10; i++) { - clockhi = swab32(readl(priv->clock_mapping)); - clocklo = swab32(readl(priv->clock_mapping + 4)); - clockhi1 = swab32(readl(priv->clock_mapping)); - if (clockhi == clockhi1) - break; - } - - cycles = (u64) clockhi << 32 | (u64) clocklo; - - return cycles; -} -EXPORT_SYMBOL_GPL(mlx4_read_clock); - - -static int map_internal_clock(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->clock_mapping = ioremap(pci_resource_start(dev->pdev, - priv->fw.clock_bar) + - priv->fw.clock_offset, MLX4_CLOCK_SIZE); - - if (!priv->clock_mapping) - return -ENOMEM; - - return 0; -} - - -int mlx4_get_internal_clock_params(struct mlx4_dev *dev, - struct mlx4_clock_params *params) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (mlx4_is_slave(dev)) - return -ENOTSUPP; - if (!params) - return -EINVAL; - - params->bar = priv->fw.clock_bar; - params->offset = priv->fw.clock_offset; - params->size = MLX4_CLOCK_SIZE; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_get_internal_clock_params); - -static void unmap_internal_clock(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (priv->clock_mapping) - iounmap(priv->clock_mapping); -} - -static void mlx4_close_hca(struct mlx4_dev *dev) -{ - unmap_internal_clock(dev); - unmap_bf_area(dev); - if (mlx4_is_slave(dev)) { - mlx4_slave_exit(dev); - } else { - mlx4_CLOSE_HCA(dev, 0); - mlx4_free_icms(dev); - - if (!mlx4_UNMAP_FA(dev)) - mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - } -} - -static int mlx4_init_slave(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 dma = (u64) priv->mfunc.vhcr_dma; - int num_of_reset_retries = NUM_OF_RESET_RETRIES; - int ret_from_reset = 0; - u32 slave_read; - u32 cmd_channel_ver; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - priv->cmd.max_cmds = 1; - mlx4_warn(dev, "Sending reset\n"); - ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, - MLX4_COMM_TIME); - /* if we are in the middle of flr the slave will try - * NUM_OF_RESET_RETRIES times before leaving.*/ - if (ret_from_reset) { - if (MLX4_DELAY_RESET_SLAVE == ret_from_reset) { - msleep(SLEEP_TIME_IN_RESET); - while (ret_from_reset && num_of_reset_retries) { - mlx4_warn(dev, "slave is currently in the" - "middle of FLR. retrying..." - "(try num:%d)\n", - (NUM_OF_RESET_RETRIES - - num_of_reset_retries + 1)); - ret_from_reset = - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, - 0, MLX4_COMM_TIME); - num_of_reset_retries = num_of_reset_retries - 1; - } - } else - goto err; - } - - /* check the driver version - the slave I/F revision - * must match the master's */ - slave_read = swab32(readl(&priv->mfunc.comm->slave_read)); - cmd_channel_ver = mlx4_comm_get_version(); - - if (MLX4_COMM_GET_IF_REV(cmd_channel_ver) != - MLX4_COMM_GET_IF_REV(slave_read)) { - mlx4_err(dev, "slave driver version is not supported" - " by the master\n"); - goto err; - } - - mlx4_warn(dev, "Sending vhcr0\n"); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR0, dma >> 48, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR1, dma >> 32, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR2, dma >> 16, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) - goto err; - - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return 0; - -err: - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return -EIO; -} - -static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev) -{ - int i; - - for (i = 1; i <= dev->caps.num_ports; i++) { - if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) - dev->caps.gid_table_len[i] = - mlx4_get_slave_num_gids(dev, 0); - else - dev->caps.gid_table_len[i] = 1; - dev->caps.pkey_table_len[i] = - dev->phys_caps.pkey_phys_table_len[i] - 1; - } -} - -static int choose_log_fs_mgm_entry_size(int qp_per_entry) -{ - int i = MLX4_MIN_MGM_LOG_ENTRY_SIZE; - - for (i = MLX4_MIN_MGM_LOG_ENTRY_SIZE; i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE; - i++) { - if (qp_per_entry <= 4 * ((1 << i) / 16 - 2)) - break; - } - - return (i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE) ? i : -1; -} - -static void choose_steering_mode(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap) -{ - int nvfs; - - mlx4_get_val(num_vfs.dbdf2val.tbl, pci_physfn(dev->pdev), 0, &nvfs); - if (high_rate_steer && !mlx4_is_mfunc(dev)) { - dev->caps.flags &= ~(MLX4_DEV_CAP_FLAG_VEP_MC_STEER | - MLX4_DEV_CAP_FLAG_VEP_UC_STEER); - dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_FS_EN; - } - - if (mlx4_log_num_mgm_entry_size == -1 && - dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN && - (!mlx4_is_mfunc(dev) || - (dev_cap->fs_max_num_qp_per_entry >= (nvfs + 1))) && - choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >= - MLX4_MIN_MGM_LOG_ENTRY_SIZE) { - dev->oper_log_mgm_entry_size = - choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry); - dev->caps.steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED; - dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry; - } else { - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER && - dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) - dev->caps.steering_mode = MLX4_STEERING_MODE_B0; - else { - dev->caps.steering_mode = MLX4_STEERING_MODE_A0; - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER || - dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) - mlx4_warn(dev, "Must have both UC_STEER and MC_STEER flags " - "set to use B0 steering. Falling back to A0 steering mode.\n"); - } - dev->oper_log_mgm_entry_size = - mlx4_log_num_mgm_entry_size > 0 ? - mlx4_log_num_mgm_entry_size : - MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; - dev->caps.num_qp_per_mgm = mlx4_get_qp_per_mgm(dev); - } - mlx4_dbg(dev, "Steering mode is: %s, oper_log_mgm_entry_size = %d, " - "log_num_mgm_entry_size = %d\n", - mlx4_steering_mode_str(dev->caps.steering_mode), - dev->oper_log_mgm_entry_size, mlx4_log_num_mgm_entry_size); -} - -static int mlx4_init_hca(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_dev_cap *dev_cap = NULL; - struct mlx4_adapter adapter; - struct mlx4_mod_stat_cfg mlx4_cfg; - struct mlx4_profile profile; - struct mlx4_init_hca_param init_hca; - u64 icm_size; - int err; - - if (!mlx4_is_slave(dev)) { - err = mlx4_QUERY_FW(dev); - if (err) { - if (err == -EACCES) - mlx4_info(dev, "non-primary physical function, skipping.\n"); - else - mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); - return err; - } - - err = mlx4_load_fw(dev); - if (err) { - mlx4_err(dev, "Failed to start FW, aborting.\n"); - return err; - } - - mlx4_cfg.log_pg_sz_m = 1; - mlx4_cfg.log_pg_sz = 0; - err = mlx4_MOD_STAT_CFG(dev, &mlx4_cfg); - if (err) - mlx4_warn(dev, "Failed to override log_pg_sz parameter\n"); - - dev_cap = kzalloc(sizeof *dev_cap, GFP_KERNEL); - if (!dev_cap) { - mlx4_err(dev, "Failed to allocate memory for dev_cap\n"); - err = -ENOMEM; - goto err_stop_fw; - } - - err = mlx4_dev_cap(dev, dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - goto err_stop_fw; - } - - choose_steering_mode(dev, dev_cap); - - if (mlx4_is_master(dev)) - mlx4_parav_master_pf_caps(dev); - - process_mod_param_profile(&profile); - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) - profile.num_mcg = MLX4_FS_NUM_MCG; - - icm_size = mlx4_make_profile(dev, &profile, dev_cap, - &init_hca); - if ((long long) icm_size < 0) { - err = icm_size; - goto err_stop_fw; - } - - dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1; - - init_hca.log_uar_sz = ilog2(dev->caps.num_uars); - init_hca.uar_page_sz = PAGE_SHIFT - 12; - - err = mlx4_init_icm(dev, dev_cap, &init_hca, icm_size); - if (err) - goto err_stop_fw; - - init_hca.mw_enable = 1; - - err = mlx4_INIT_HCA(dev, &init_hca); - if (err) { - mlx4_err(dev, "INIT_HCA command failed, aborting.\n"); - goto err_free_icm; - } - - /* - * Read HCA frequency by QUERY_HCA command - */ - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) { - memset(&init_hca, 0, sizeof(init_hca)); - err = mlx4_QUERY_HCA(dev, &init_hca); - if (err) { - mlx4_err(dev, "QUERY_HCA command failed, disable timestamp.\n"); - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - } else { - dev->caps.hca_core_clock = - init_hca.hca_core_clock; - } - - /* In case we got HCA frequency 0 - disable timestamping - * to avoid dividing by zero - */ - if (!dev->caps.hca_core_clock) { - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_err(dev, "HCA frequency is 0. Timestamping is not supported."); - } else if (map_internal_clock(dev)) { - /* Map internal clock, - * in case of failure disable timestamping - */ - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported.\n"); - } - } - } else { - err = mlx4_init_slave(dev); - if (err) { - mlx4_err(dev, "Failed to initialize slave\n"); - return err; - } - - err = mlx4_slave_cap(dev); - if (err) { - mlx4_err(dev, "Failed to obtain slave caps\n"); - goto err_close; - } - } - - if (map_bf_area(dev)) - mlx4_dbg(dev, "Failed to map blue flame area\n"); - - /* Only the master set the ports, all the rest got it from it.*/ - if (!mlx4_is_slave(dev)) - mlx4_set_port_mask(dev); - - err = mlx4_QUERY_ADAPTER(dev, &adapter); - if (err) { - mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); - goto unmap_bf; - } - - priv->eq_table.inta_pin = adapter.inta_pin; - memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); - memcpy(dev->vsd, adapter.vsd, sizeof(dev->vsd)); - dev->vsd_vendor_id = adapter.vsd_vendor_id; - - if (!mlx4_is_slave(dev)) - kfree(dev_cap); - - return 0; - -unmap_bf: - if (!mlx4_is_slave(dev)) - unmap_internal_clock(dev); - unmap_bf_area(dev); - - if (mlx4_is_slave(dev)) { - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - } - -err_close: - if (mlx4_is_slave(dev)) - mlx4_slave_exit(dev); - else - mlx4_CLOSE_HCA(dev, 0); - -err_free_icm: - if (!mlx4_is_slave(dev)) - mlx4_free_icms(dev); - -err_stop_fw: - if (!mlx4_is_slave(dev)) { - if (!mlx4_UNMAP_FA(dev)) - mlx4_free_icm(dev, priv->fw.fw_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - kfree(dev_cap); - } - return err; -} - -static int mlx4_init_counters_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int nent_pow2, port_indx, vf_index, num_counters; - int res, index = 0; - struct counter_index *new_counter_index; - - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)) - return -ENOENT; - - if (!mlx4_is_slave(dev) && - dev->caps.max_counters == dev->caps.max_extended_counters) { - res = mlx4_cmd(dev, MLX4_IF_STATE_EXTENDED, 0, 0, - MLX4_CMD_SET_IF_STAT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (res) { - mlx4_err(dev, "Failed to set extended counters (err=%d)\n", res); - return res; - } - } - - mutex_init(&priv->counters_table.mutex); - - if (mlx4_is_slave(dev)) { - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.global_port_list[port_indx]); - if (dev->caps.def_counter_index[port_indx] != 0xFF) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - new_counter_index->index = dev->caps.def_counter_index[port_indx]; - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port_indx]); - } - } - mlx4_dbg(dev, "%s: slave allocated %d counters for %d ports\n", - __func__, dev->caps.num_ports, dev->caps.num_ports); - return 0; - } - - nent_pow2 = roundup_pow_of_two(dev->caps.max_counters); - - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.global_port_list[port_indx]); - /* allocating 2 counters per port for PFs */ - /* For the PF, the ETH default counters are 0,2; */ - /* and the RoCE default counters are 1,3 */ - for (num_counters = 0; num_counters < 2; num_counters++, index++) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - new_counter_index->index = index; - list_add_tail(&new_counter_index->list, - &priv->counters_table.global_port_list[port_indx]); - } - } - - if (mlx4_is_master(dev)) { - for (vf_index = 0; vf_index < dev->num_vfs; vf_index++) { - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.vf_list[vf_index][port_indx]); - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - if (index < nent_pow2 - 2) { - new_counter_index->index = index; - index++; - } else { - new_counter_index->index = MLX4_SINK_COUNTER_INDEX; - } - - list_add_tail(&new_counter_index->list, - &priv->counters_table.vf_list[vf_index][port_indx]); - } - } - - res = mlx4_bitmap_init(&priv->counters_table.bitmap, - nent_pow2, nent_pow2 - 1, - index, 1); - mlx4_dbg(dev, "%s: master allocated %d counters for %d VFs\n", - __func__, index, dev->num_vfs); - } else { - res = mlx4_bitmap_init(&priv->counters_table.bitmap, - nent_pow2, nent_pow2 - 1, - index, 1); - mlx4_dbg(dev, "%s: native allocated %d counters for %d ports\n", - __func__, index, dev->caps.num_ports); - } - - return 0; - -} - -static void mlx4_cleanup_counters_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, j; - struct counter_index *port, *tmp_port; - struct counter_index *vf, *tmp_vf; - - mutex_lock(&priv->counters_table.mutex); - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) { - for (i = 0; i < dev->caps.num_ports; i++) { - list_for_each_entry_safe(port, tmp_port, - &priv->counters_table.global_port_list[i], - list) { - list_del(&port->list); - kfree(port); - } - } - if (!mlx4_is_slave(dev)) { - for (i = 0; i < dev->num_vfs; i++) { - for (j = 0; j < dev->caps.num_ports; j++) { - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[i][j], - list) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - list_del(&vf->list); - kfree(vf); - } - } - } - mlx4_bitmap_cleanup(&priv->counters_table.bitmap); - } - } - mutex_unlock(&priv->counters_table.mutex); -} - -int __mlx4_slave_counters_free(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, first; - struct counter_index *vf, *tmp_vf; - - /* clean VF's counters for the next useg */ - if (slave > 0 && slave <= dev->num_vfs) { - mlx4_dbg(dev, "%s: free counters of slave(%d)\n" - , __func__, slave); - - mutex_lock(&priv->counters_table.mutex); - for (i = 0; i < dev->caps.num_ports; i++) { - first = 0; - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[slave - 1][i], - list) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - if (first++ && vf->index != MLX4_SINK_COUNTER_INDEX) { - mlx4_dbg(dev, "%s: delete counter index %d for slave %d and port %d\n" - , __func__, vf->index, slave, i + 1); - mlx4_bitmap_free(&priv->counters_table.bitmap, vf->index, MLX4_USE_RR); - list_del(&vf->list); - kfree(vf); - } else { - mlx4_dbg(dev, "%s: can't delete default counter index %d for slave %d and port %d\n" - , __func__, vf->index, slave, i + 1); - } - } - } - mutex_unlock(&priv->counters_table.mutex); - } - - return 0; -} - -int __mlx4_counter_alloc(struct mlx4_dev *dev, int slave, int port, u32 *idx) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index; - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)) - return -ENOENT; - - if ((slave > MLX4_MAX_NUM_VF) || (slave < 0) || - (port < 0) || (port > MLX4_MAX_PORTS)) { - mlx4_dbg(dev, "%s: invalid slave(%d) or port(%d) index\n", - __func__, slave, port); - return -EINVAL; - } - - /* handle old guest request does not support request by port index */ - if (port == 0) { - *idx = MLX4_SINK_COUNTER_INDEX; - mlx4_dbg(dev, "%s: allocated default counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); - return 0; - } - - mutex_lock(&priv->counters_table.mutex); - - *idx = mlx4_bitmap_alloc(&priv->counters_table.bitmap); - /* if no resources return the default counter of the slave and port */ - if (*idx == -1) { - if (slave == 0) { /* its the ethernet counter ?????? */ - new_counter_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - } else { - new_counter_index = list_entry(priv->counters_table.vf_list[slave - 1][port - 1].next, - struct counter_index, - list); - } - - *idx = new_counter_index->index; - mlx4_dbg(dev, "%s: allocated defualt counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); - goto out; - } - - if (slave == 0) { /* native or master */ - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - goto no_mem; - new_counter_index->index = *idx; - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port - 1]); - } else { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - goto no_mem; - new_counter_index->index = *idx; - list_add_tail(&new_counter_index->list, &priv->counters_table.vf_list[slave - 1][port - 1]); - } - - mlx4_dbg(dev, "%s: allocated counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); -out: - mutex_unlock(&priv->counters_table.mutex); - return 0; - -no_mem: - mlx4_bitmap_free(&priv->counters_table.bitmap, *idx, MLX4_USE_RR); - mutex_unlock(&priv->counters_table.mutex); - *idx = MLX4_SINK_COUNTER_INDEX; - mlx4_dbg(dev, "%s: failed err (%d)\n" - , __func__, -ENOMEM); - return -ENOMEM; -} - -int mlx4_counter_alloc(struct mlx4_dev *dev, u8 port, u32 *idx) -{ - u64 out_param; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index, *c_index; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, - ((u32) port) << 8 | (u32) RES_COUNTER, - RES_OP_RESERVE, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) { - *idx = get_param_l(&out_param); - if (*idx == MLX4_SINK_COUNTER_INDEX) - return -ENOSPC; - - mutex_lock(&priv->counters_table.mutex); - c_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - mutex_unlock(&priv->counters_table.mutex); - if (c_index->index == *idx) - return -EEXIST; - - if (mlx4_is_slave(dev)) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) { - mlx4_counter_free(dev, port, *idx); - return -ENOMEM; - } - new_counter_index->index = *idx; - mutex_lock(&priv->counters_table.mutex); - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port - 1]); - mutex_unlock(&priv->counters_table.mutex); - mlx4_dbg(dev, "%s: allocated counter index %d for port %d\n" - , __func__, *idx, port); - } - } - return err; - } - return __mlx4_counter_alloc(dev, 0, port, idx); -} -EXPORT_SYMBOL_GPL(mlx4_counter_alloc); - -void __mlx4_counter_free(struct mlx4_dev *dev, int slave, int port, u32 idx) -{ - /* check if native or slave and deletes accordingly */ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *pf, *tmp_pf; - struct counter_index *vf, *tmp_vf; - int first; - - - if (idx == MLX4_SINK_COUNTER_INDEX) { - mlx4_dbg(dev, "%s: try to delete default counter index %d for port %d\n" - , __func__, idx, port); - return; - } - - if ((slave > MLX4_MAX_NUM_VF) || (slave < 0) || - (port < 0) || (port > MLX4_MAX_PORTS)) { - mlx4_warn(dev, "%s: deletion failed due to invalid slave(%d) or port(%d) index\n" - , __func__, slave, idx); - return; - } - - mutex_lock(&priv->counters_table.mutex); - if (slave == 0) { - first = 0; - list_for_each_entry_safe(pf, tmp_pf, - &priv->counters_table.global_port_list[port - 1], - list) { - /* the first 2 counters are reserved */ - if (pf->index == idx) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, pf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, pf->index); - if (1 < first && idx != MLX4_SINK_COUNTER_INDEX) { - list_del(&pf->list); - kfree(pf); - mlx4_dbg(dev, "%s: delete counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - mlx4_bitmap_free(&priv->counters_table.bitmap, idx, MLX4_USE_RR); - goto out; - } else { - mlx4_dbg(dev, "%s: can't delete default counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - goto out; - } - } - first++; - } - mlx4_dbg(dev, "%s: can't delete counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - } else { - first = 0; - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[slave - 1][port - 1], - list) { - /* the first element is reserved */ - if (vf->index == idx) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - if (first) { - list_del(&vf->list); - kfree(vf); - mlx4_dbg(dev, "%s: delete counter index %d for slave %d port %d\n", - __func__, idx, slave, port); - mlx4_bitmap_free(&priv->counters_table.bitmap, idx, MLX4_USE_RR); - goto out; - } else { - mlx4_dbg(dev, "%s: can't delete default slave (%d) counter index %d for port %d\n" - , __func__, slave, idx, port); - goto out; - } - } - first++; - } - mlx4_dbg(dev, "%s: can't delete slave (%d) counter index %d for port %d\n" - , __func__, slave, idx, port); - } - -out: - mutex_unlock(&priv->counters_table.mutex); -} - -void mlx4_counter_free(struct mlx4_dev *dev, u8 port, u32 idx) -{ - u64 in_param = 0; - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *counter, *tmp_counter; - int first = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, idx); - mlx4_cmd(dev, in_param, - ((u32) port) << 8 | (u32) RES_COUNTER, - RES_OP_RESERVE, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - - if (mlx4_is_slave(dev) && idx != MLX4_SINK_COUNTER_INDEX) { - mutex_lock(&priv->counters_table.mutex); - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.global_port_list[port - 1], - list) { - if (counter->index == idx && first++) { - list_del(&counter->list); - kfree(counter); - mlx4_dbg(dev, "%s: delete counter index %d for port %d\n" - , __func__, idx, port); - mutex_unlock(&priv->counters_table.mutex); - return; - } - } - mutex_unlock(&priv->counters_table.mutex); - } - - return; - } - __mlx4_counter_free(dev, 0, port, idx); -} -EXPORT_SYMBOL_GPL(mlx4_counter_free); - -int __mlx4_clear_if_stat(struct mlx4_dev *dev, - u8 counter_index) -{ - struct mlx4_cmd_mailbox *if_stat_mailbox = NULL; - int err = 0; - u32 if_stat_in_mod = (counter_index & 0xff) | (1 << 31); - - if (counter_index == MLX4_SINK_COUNTER_INDEX) - return -EINVAL; - - if (mlx4_is_slave(dev)) - return 0; - - if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(if_stat_mailbox)) { - err = PTR_ERR(if_stat_mailbox); - return err; - } - - err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, if_stat_in_mod, 0, - MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, if_stat_mailbox); - return err; -} - -u8 mlx4_get_default_counter_index(struct mlx4_dev *dev, int slave, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB) { - mlx4_dbg(dev, "%s: return counter index %d for slave %d port (MLX4_PORT_TYPE_IB) %d\n", - __func__, MLX4_SINK_COUNTER_INDEX, slave, port); - return (u8)MLX4_SINK_COUNTER_INDEX; - } - - mutex_lock(&priv->counters_table.mutex); - if (slave == 0) { - new_counter_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - } else { - new_counter_index = list_entry(priv->counters_table.vf_list[slave - 1][port - 1].next, - struct counter_index, - list); - } - mutex_unlock(&priv->counters_table.mutex); - - mlx4_dbg(dev, "%s: return counter index %d for slave %d port %d\n", - __func__, new_counter_index->index, slave, port); - - - return (u8)new_counter_index->index; -} - -int mlx4_get_vport_ethtool_stats(struct mlx4_dev *dev, int port, - struct mlx4_en_vport_stats *vport_stats, - int reset) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *if_stat_mailbox = NULL; - union mlx4_counter *counter; - int err = 0; - u32 if_stat_in_mod; - struct counter_index *vport, *tmp_vport; - - if (!vport_stats) - return -EINVAL; - - if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(if_stat_mailbox)) { - err = PTR_ERR(if_stat_mailbox); - return err; - } - - mutex_lock(&priv->counters_table.mutex); - list_for_each_entry_safe(vport, tmp_vport, - &priv->counters_table.global_port_list[port - 1], - list) { - if (vport->index == MLX4_SINK_COUNTER_INDEX) - continue; - - memset(if_stat_mailbox->buf, 0, sizeof(union mlx4_counter)); - if_stat_in_mod = (vport->index & 0xff) | ((reset & 1) << 31); - err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, - if_stat_in_mod, 0, - MLX4_CMD_QUERY_IF_STAT, - MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (err) { - mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n", - __func__, vport->index); - goto if_stat_out; - } - counter = (union mlx4_counter *)if_stat_mailbox->buf; - if ((counter->control.cnt_mode & 0xf) == 1) { - vport_stats->rx_broadcast_packets += be64_to_cpu(counter->ext.counters[0].IfRxBroadcastFrames); - vport_stats->rx_unicast_packets += be64_to_cpu(counter->ext.counters[0].IfRxUnicastFrames); - vport_stats->rx_multicast_packets += be64_to_cpu(counter->ext.counters[0].IfRxMulticastFrames); - vport_stats->tx_broadcast_packets += be64_to_cpu(counter->ext.counters[0].IfTxBroadcastFrames); - vport_stats->tx_unicast_packets += be64_to_cpu(counter->ext.counters[0].IfTxUnicastFrames); - vport_stats->tx_multicast_packets += be64_to_cpu(counter->ext.counters[0].IfTxMulticastFrames); - vport_stats->rx_broadcast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxBroadcastOctets); - vport_stats->rx_unicast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxUnicastOctets); - vport_stats->rx_multicast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxMulticastOctets); - vport_stats->tx_broadcast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxBroadcastOctets); - vport_stats->tx_unicast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxUnicastOctets); - vport_stats->tx_multicast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxMulticastOctets); - vport_stats->rx_errors += be64_to_cpu(counter->ext.counters[0].IfRxErrorFrames); - vport_stats->rx_dropped += be64_to_cpu(counter->ext.counters[0].IfRxNoBufferFrames); - vport_stats->tx_errors += be64_to_cpu(counter->ext.counters[0].IfTxDroppedFrames); - } - } - -if_stat_out: - mutex_unlock(&priv->counters_table.mutex); - mlx4_free_cmd_mailbox(dev, if_stat_mailbox); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_get_vport_ethtool_stats); - -static int mlx4_setup_hca(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int port; - __be32 ib_port_default_caps; - - err = mlx4_init_uar_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "user access region table (err=%d), aborting.\n", - err); - return err; - } - - err = mlx4_uar_alloc(dev, &priv->driver_uar); - if (err) { - mlx4_err(dev, "Failed to allocate driver access region " - "(err=%d), aborting.\n", err); - goto err_uar_table_free; - } - - priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); - if (!priv->kar) { - mlx4_err(dev, "Couldn't map kernel access region, " - "aborting.\n"); - err = -ENOMEM; - goto err_uar_free; - } - - err = mlx4_init_pd_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "protection domain table (err=%d), aborting.\n", err); - goto err_kar_unmap; - } - - err = mlx4_init_xrcd_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "reliable connection domain table (err=%d), " - "aborting.\n", err); - goto err_pd_table_free; - } - - err = mlx4_init_mr_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "memory region table (err=%d), aborting.\n", err); - goto err_xrcd_table_free; - } - - if (!mlx4_is_slave(dev)) { - err = mlx4_init_mcg_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "multicast group table (err=%d), aborting.\n", - err); - goto err_mr_table_free; - } - } - - err = mlx4_init_eq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "event queue table (err=%d), aborting.\n", err); - goto err_mcg_table_free; - } - - err = mlx4_cmd_use_events(dev); - if (err) { - mlx4_err(dev, "Failed to switch to event-driven " - "firmware commands (err=%d), aborting.\n", err); - goto err_eq_table_free; - } - - err = mlx4_NOP(dev); - if (err) { - if (dev->flags & MLX4_FLAG_MSI_X) { - mlx4_warn(dev, "NOP command failed to generate MSI-X " - "interrupt IRQ %d).\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); - mlx4_warn(dev, "Trying again without MSI-X.\n"); - } else { - mlx4_err(dev, "NOP command failed to generate interrupt " - "(IRQ %d), aborting.\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); - mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); - } - - goto err_cmd_poll; - } - - mlx4_dbg(dev, "NOP command IRQ test passed\n"); - - err = mlx4_init_cq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "completion queue table (err=%d), aborting.\n", err); - goto err_cmd_poll; - } - - err = mlx4_init_srq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "shared receive queue table (err=%d), aborting.\n", - err); - goto err_cq_table_free; - } - - err = mlx4_init_qp_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "queue pair table (err=%d), aborting.\n", err); - goto err_srq_table_free; - } - - err = mlx4_init_counters_table(dev); - if (err && err != -ENOENT) { - mlx4_err(dev, "Failed to initialize counters table (err=%d), " - "aborting.\n", err); - goto err_qp_table_free; - } - - if (!mlx4_is_slave(dev)) { - for (port = 1; port <= dev->caps.num_ports; port++) { - ib_port_default_caps = 0; - err = mlx4_get_port_ib_caps(dev, port, - &ib_port_default_caps); - if (err) - mlx4_warn(dev, "failed to get port %d default " - "ib capabilities (%d). Continuing " - "with caps = 0\n", port, err); - dev->caps.ib_port_def_cap[port] = ib_port_default_caps; - - /* initialize per-slave default ib port capabilities */ - if (mlx4_is_master(dev)) { - int i; - for (i = 0; i < dev->num_slaves; i++) { - if (i == mlx4_master_func_num(dev)) - continue; - priv->mfunc.master.slave_state[i].ib_cap_mask[port] = - ib_port_default_caps; - } - } - - dev->caps.port_ib_mtu[port] = IB_MTU_4096; - - err = mlx4_SET_PORT(dev, port, mlx4_is_master(dev) ? - dev->caps.pkey_table_len[port] : -1); - if (err) { - mlx4_err(dev, "Failed to set port %d (err=%d), " - "aborting\n", port, err); - goto err_counters_table_free; - } - } - } - - return 0; - -err_counters_table_free: - mlx4_cleanup_counters_table(dev); - -err_qp_table_free: - mlx4_cleanup_qp_table(dev); - -err_srq_table_free: - mlx4_cleanup_srq_table(dev); - -err_cq_table_free: - mlx4_cleanup_cq_table(dev); - -err_cmd_poll: - mlx4_cmd_use_polling(dev); - -err_eq_table_free: - mlx4_cleanup_eq_table(dev); - -err_mcg_table_free: - if (!mlx4_is_slave(dev)) - mlx4_cleanup_mcg_table(dev); - -err_mr_table_free: - mlx4_cleanup_mr_table(dev); - -err_xrcd_table_free: - mlx4_cleanup_xrcd_table(dev); - -err_pd_table_free: - mlx4_cleanup_pd_table(dev); - -err_kar_unmap: - iounmap(priv->kar); - -err_uar_free: - mlx4_uar_free(dev, &priv->driver_uar); - -err_uar_table_free: - mlx4_cleanup_uar_table(dev); - return err; -} - -static void mlx4_enable_msi_x(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct msix_entry *entries; - int nreq = min_t(int, dev->caps.num_ports * - min_t(int, num_possible_cpus() + 1, MAX_MSIX_P_PORT) - + MSIX_LEGACY_SZ, MAX_MSIX); - int err; - int i; - - if (msi_x) { - nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, - nreq); - - if (msi_x > 1 && !mlx4_is_mfunc(dev)) - nreq = min_t(int, nreq, msi_x); - - entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); - if (!entries) - goto no_msi; - - for (i = 0; i < nreq; ++i) - entries[i].entry = i; - - retry: - err = pci_enable_msix(dev->pdev, entries, nreq); - if (err) { - /* Try again if at least 2 vectors are available */ - if (err > 1) { - mlx4_info(dev, "Requested %d vectors, " - "but only %d MSI-X vectors available, " - "trying again\n", nreq, err); - nreq = err; - goto retry; - } - kfree(entries); - /* if error, or can't alloc even 1 IRQ */ - if (err < 0) { - mlx4_err(dev, "No IRQs left, device can't " - "be started.\n"); - goto no_irq; - } - goto no_msi; - } - - if (nreq < - MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { - /*Working in legacy mode , all EQ's shared*/ - dev->caps.comp_pool = 0; - dev->caps.num_comp_vectors = nreq - 1; - } else { - dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; - dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; - } - for (i = 0; i < nreq; ++i) - priv->eq_table.eq[i].irq = entries[i].vector; - - dev->flags |= MLX4_FLAG_MSI_X; - - kfree(entries); - return; - } - -no_msi: - dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; - - for (i = 0; i < 2; ++i) - priv->eq_table.eq[i].irq = dev->pdev->irq; - return; -no_irq: - dev->caps.num_comp_vectors = 0; - dev->caps.comp_pool = 0; - return; -} - -static void -mlx4_init_hca_info(struct mlx4_dev *dev) -{ - struct mlx4_hca_info *info = &mlx4_priv(dev)->hca_info; - - info->dev = dev; - - info->firmware_attr = (struct device_attribute)__ATTR(fw_ver, S_IRUGO, - show_firmware_version, NULL); - if (device_create_file(&dev->pdev->dev, &info->firmware_attr)) - mlx4_err(dev, "Failed to add file firmware version"); - - info->hca_attr = (struct device_attribute)__ATTR(hca, S_IRUGO, show_hca, - NULL); - if (device_create_file(&dev->pdev->dev, &info->hca_attr)) - mlx4_err(dev, "Failed to add file hca type"); - - info->board_attr = (struct device_attribute)__ATTR(board_id, S_IRUGO, - show_board, NULL); - if (device_create_file(&dev->pdev->dev, &info->board_attr)) - mlx4_err(dev, "Failed to add file board id type"); -} - -static int mlx4_init_port_info(struct mlx4_dev *dev, int port) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - int err = 0; - - info->dev = dev; - info->port = port; - if (!mlx4_is_slave(dev)) { - mlx4_init_mac_table(dev, &info->mac_table); - mlx4_init_vlan_table(dev, &info->vlan_table); - info->base_qpn = mlx4_get_base_qpn(dev, port); - } - - sprintf(info->dev_name, "mlx4_port%d", port); - info->port_attr.attr.name = info->dev_name; - if (mlx4_is_mfunc(dev)) - info->port_attr.attr.mode = S_IRUGO; - else { - info->port_attr.attr.mode = S_IRUGO | S_IWUSR; - info->port_attr.store = set_port_type; - } - info->port_attr.show = show_port_type; - sysfs_attr_init(&info->port_attr.attr); - - err = device_create_file(&dev->pdev->dev, &info->port_attr); - if (err) { - mlx4_err(dev, "Failed to create file for port %d\n", port); - info->port = -1; - } - - sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); - info->port_mtu_attr.attr.name = info->dev_mtu_name; - if (mlx4_is_mfunc(dev)) - info->port_mtu_attr.attr.mode = S_IRUGO; - else { - info->port_mtu_attr.attr.mode = S_IRUGO | S_IWUSR; - info->port_mtu_attr.store = set_port_ib_mtu; - } - info->port_mtu_attr.show = show_port_ib_mtu; - sysfs_attr_init(&info->port_mtu_attr.attr); - - err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr); - if (err) { - mlx4_err(dev, "Failed to create mtu file for port %d\n", port); - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - info->port = -1; - } - - return err; -} - -static void -mlx4_cleanup_hca_info(struct mlx4_hca_info *info) -{ - device_remove_file(&info->dev->pdev->dev, &info->firmware_attr); - device_remove_file(&info->dev->pdev->dev, &info->board_attr); - device_remove_file(&info->dev->pdev->dev, &info->hca_attr); -} - -static void mlx4_cleanup_port_info(struct mlx4_port_info *info) -{ - if (info->port < 0) - return; - - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr); -} - -static int mlx4_init_steering(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int num_entries = dev->caps.num_ports; - int i, j; - - priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); - if (!priv->steer) - return -ENOMEM; - - for (i = 0; i < num_entries; i++) - for (j = 0; j < MLX4_NUM_STEERS; j++) { - INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]); - INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]); - } - return 0; -} - -static void mlx4_clear_steering(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_steer_index *entry, *tmp_entry; - struct mlx4_promisc_qp *pqp, *tmp_pqp; - int num_entries = dev->caps.num_ports; - int i, j; - - for (i = 0; i < num_entries; i++) { - for (j = 0; j < MLX4_NUM_STEERS; j++) { - list_for_each_entry_safe(pqp, tmp_pqp, - &priv->steer[i].promisc_qps[j], - list) { - list_del(&pqp->list); - kfree(pqp); - } - list_for_each_entry_safe(entry, tmp_entry, - &priv->steer[i].steer_entries[j], - list) { - list_del(&entry->list); - list_for_each_entry_safe(pqp, tmp_pqp, - &entry->duplicates, - list) { - list_del(&pqp->list); - kfree(pqp); - } - kfree(entry); - } - } - } - kfree(priv->steer); -} - -static int extended_func_num(struct pci_dev *pdev) -{ - return PCI_SLOT(pdev->devfn) * 8 + PCI_FUNC(pdev->devfn); -} - -#define MLX4_OWNER_BASE 0x8069c -#define MLX4_OWNER_SIZE 4 - -static int mlx4_get_ownership(struct mlx4_dev *dev) -{ - void __iomem *owner; - u32 ret; - - if (pci_channel_offline(dev->pdev)) - return -EIO; - - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, - MLX4_OWNER_SIZE); - if (!owner) { - mlx4_err(dev, "Failed to obtain ownership bit\n"); - return -ENOMEM; - } - - ret = readl(owner); - iounmap(owner); - return (int) !!ret; -} - -static void mlx4_free_ownership(struct mlx4_dev *dev) -{ - void __iomem *owner; - - if (pci_channel_offline(dev->pdev)) - return; - - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, - MLX4_OWNER_SIZE); - if (!owner) { - mlx4_err(dev, "Failed to obtain ownership bit\n"); - return; - } - writel(0, owner); - msleep(1000); - iounmap(owner); -} - -static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) -{ - struct mlx4_priv *priv; - struct mlx4_dev *dev; - int err; - int port; - int nvfs, prb_vf; - - pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev)); - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Cannot enable PCI device, " - "aborting.\n"); - return err; - } - - mlx4_get_val(num_vfs.dbdf2val.tbl, pci_physfn(pdev), 0, &nvfs); - mlx4_get_val(probe_vf.dbdf2val.tbl, pci_physfn(pdev), 0, &prb_vf); - if (nvfs > MLX4_MAX_NUM_VF) { - dev_err(&pdev->dev, "There are more VF's (%d) than allowed(%d)\n", - nvfs, MLX4_MAX_NUM_VF); - return -EINVAL; - } - - if (nvfs < 0) { - dev_err(&pdev->dev, "num_vfs module parameter cannot be negative\n"); - return -EINVAL; - } - /* - * Check for BARs. - */ - if (!(pci_dev_data & MLX4_PCI_DEV_IS_VF) && - !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "Missing DCS, aborting." - "(driver_data: 0x%x, pci_resource_flags(pdev, 0):0x%x)\n", - pci_dev_data, pci_resource_flags(pdev, 0)); - err = -ENODEV; - goto err_disable_pdev; - } - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "Missing UAR, aborting.\n"); - err = -ENODEV; - goto err_disable_pdev; - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); - goto err_disable_pdev; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); - goto err_release_regions; - } - } - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " - "consistent PCI DMA mask.\n"); - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " - "aborting.\n"); - goto err_release_regions; - } - } - - /* Allow large DMA segments, up to the firmware limit of 1 GB */ - dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); - - priv = kzalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "Device struct alloc failed, " - "aborting.\n"); - err = -ENOMEM; - goto err_release_regions; - } - - dev = &priv->dev; - dev->pdev = pdev; - INIT_LIST_HEAD(&priv->dev_list); - INIT_LIST_HEAD(&priv->ctx_list); - spin_lock_init(&priv->ctx_lock); - - mutex_init(&priv->port_mutex); - - INIT_LIST_HEAD(&priv->pgdir_list); - mutex_init(&priv->pgdir_mutex); - - INIT_LIST_HEAD(&priv->bf_list); - mutex_init(&priv->bf_mutex); - - dev->rev_id = pdev->revision; - dev->numa_node = dev_to_node(&pdev->dev); - /* Detect if this device is a virtual function */ - if (pci_dev_data & MLX4_PCI_DEV_IS_VF) { - /* When acting as pf, we normally skip vfs unless explicitly - * requested to probe them. */ - if (nvfs && extended_func_num(pdev) > prb_vf) { - mlx4_warn(dev, "Skipping virtual function:%d\n", - extended_func_num(pdev)); - err = -ENODEV; - goto err_free_dev; - } - mlx4_warn(dev, "Detected virtual function - running in slave mode\n"); - dev->flags |= MLX4_FLAG_SLAVE; - } else { - /* We reset the device and enable SRIOV only for physical - * devices. Try to claim ownership on the device; - * if already taken, skip -- do not allow multiple PFs */ - err = mlx4_get_ownership(dev); - if (err) { - if (err < 0) - goto err_free_dev; - else { - mlx4_warn(dev, "Multiple PFs not yet supported." - " Skipping PF.\n"); - err = -EINVAL; - goto err_free_dev; - } - } - - if (nvfs) { - mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", nvfs); - err = pci_enable_sriov(pdev, nvfs); - if (err) { - mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n", - err); - err = 0; - } else { - mlx4_warn(dev, "Running in master mode\n"); - dev->flags |= MLX4_FLAG_SRIOV | - MLX4_FLAG_MASTER; - dev->num_vfs = nvfs; - } - } - - atomic_set(&priv->opreq_count, 0); - INIT_WORK(&priv->opreq_task, mlx4_opreq_action); - - /* - * Now reset the HCA before we touch the PCI capabilities or - * attempt a firmware command, since a boot ROM may have left - * the HCA in an undefined state. - */ - err = mlx4_reset(dev); - if (err) { - mlx4_err(dev, "Failed to reset HCA, aborting.\n"); - goto err_sriov; - } - } - -slave_start: - err = mlx4_cmd_init(dev); - if (err) { - mlx4_err(dev, "Failed to init command interface, aborting.\n"); - goto err_sriov; - } - - /* In slave functions, the communication channel must be initialized - * before posting commands. Also, init num_slaves before calling - * mlx4_init_hca */ - if (mlx4_is_mfunc(dev)) { - if (mlx4_is_master(dev)) - dev->num_slaves = MLX4_MAX_NUM_SLAVES; - else { - dev->num_slaves = 0; - err = mlx4_multi_func_init(dev); - if (err) { - mlx4_err(dev, "Failed to init slave mfunc" - " interface, aborting.\n"); - goto err_cmd; - } - } - } - - err = mlx4_init_hca(dev); - if (err) { - if (err == -EACCES) { - /* Not primary Physical function - * Running in slave mode */ - mlx4_cmd_cleanup(dev); - dev->flags |= MLX4_FLAG_SLAVE; - dev->flags &= ~MLX4_FLAG_MASTER; - goto slave_start; - } else - goto err_mfunc; - } - - /* In master functions, the communication channel must be initialized - * after obtaining its address from fw */ - if (mlx4_is_master(dev)) { - err = mlx4_multi_func_init(dev); - if (err) { - mlx4_err(dev, "Failed to init master mfunc" - "interface, aborting.\n"); - goto err_close; - } - } - - err = mlx4_alloc_eq_table(dev); - if (err) - goto err_master_mfunc; - - priv->msix_ctl.pool_bm = 0; - mutex_init(&priv->msix_ctl.pool_lock); - - mlx4_enable_msi_x(dev); - - /* no MSIX and no shared IRQ */ - if (!dev->caps.num_comp_vectors && !dev->caps.comp_pool) { - err = -ENOSPC; - goto err_free_eq; - } - - if ((mlx4_is_mfunc(dev)) && - !(dev->flags & MLX4_FLAG_MSI_X)) { - err = -ENOSYS; - mlx4_err(dev, "INTx is not supported in multi-function mode." - " aborting.\n"); - goto err_free_eq; - } - - if (!mlx4_is_slave(dev)) { - err = mlx4_init_steering(dev); - if (err) - goto err_free_eq; - } - - err = mlx4_setup_hca(dev); - if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X) && - !mlx4_is_mfunc(dev)) { - dev->flags &= ~MLX4_FLAG_MSI_X; - dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; - pci_disable_msix(pdev); - err = mlx4_setup_hca(dev); - } - - if (err) - goto err_steer; - - mlx4_init_quotas(dev); - mlx4_init_hca_info(dev); - - for (port = 1; port <= dev->caps.num_ports; port++) { - err = mlx4_init_port_info(dev, port); - if (err) - goto err_port; - } - - err = mlx4_register_device(dev); - if (err) - goto err_port; - - mlx4_request_modules(dev); - - mlx4_sense_init(dev); - mlx4_start_sense(dev); - - priv->pci_dev_data = pci_dev_data; - pci_set_drvdata(pdev, dev); - - return 0; - -err_port: - for (--port; port >= 1; --port) - mlx4_cleanup_port_info(&priv->port[port]); - - mlx4_cleanup_counters_table(dev); - mlx4_cleanup_qp_table(dev); - mlx4_cleanup_srq_table(dev); - mlx4_cleanup_cq_table(dev); - mlx4_cmd_use_polling(dev); - mlx4_cleanup_eq_table(dev); - mlx4_cleanup_mcg_table(dev); - mlx4_cleanup_mr_table(dev); - mlx4_cleanup_xrcd_table(dev); - mlx4_cleanup_pd_table(dev); - mlx4_cleanup_uar_table(dev); - -err_steer: - if (!mlx4_is_slave(dev)) - mlx4_clear_steering(dev); - -err_free_eq: - mlx4_free_eq_table(dev); - -err_master_mfunc: - if (mlx4_is_master(dev)) { - mlx4_free_resource_tracker(dev, RES_TR_FREE_STRUCTS_ONLY); - mlx4_multi_func_cleanup(dev); - } - - if (mlx4_is_slave(dev)) { - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - } - -err_close: - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - - mlx4_close_hca(dev); - -err_mfunc: - if (mlx4_is_slave(dev)) - mlx4_multi_func_cleanup(dev); - -err_cmd: - mlx4_cmd_cleanup(dev); - -err_sriov: - if (dev->flags & MLX4_FLAG_SRIOV) - pci_disable_sriov(pdev); - - if (!mlx4_is_slave(dev)) - mlx4_free_ownership(dev); - -err_free_dev: - kfree(priv); - -err_release_regions: - pci_release_regions(pdev); - -err_disable_pdev: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - return err; -} - -static int __devinit mlx4_init_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - device_set_desc(pdev->dev.bsddev, mlx4_version); - return __mlx4_init_one(pdev, id->driver_data); -} - -static void mlx4_remove_one(struct pci_dev *pdev) -{ - struct mlx4_dev *dev = pci_get_drvdata(pdev); - struct mlx4_priv *priv = mlx4_priv(dev); - int p; - - if (dev) { - /* in SRIOV it is not allowed to unload the pf's - * driver while there are alive vf's */ - if (mlx4_is_master(dev)) { - if (mlx4_how_many_lives_vf(dev)) - mlx4_err(dev, "Removing PF when there are assigned VF's !!!\n"); - } - mlx4_stop_sense(dev); - mlx4_unregister_device(dev); - - mlx4_cleanup_hca_info(&priv->hca_info); - for (p = 1; p <= dev->caps.num_ports; p++) { - mlx4_cleanup_port_info(&priv->port[p]); - mlx4_CLOSE_PORT(dev, p); - } - - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_SLAVES_ONLY); - - mlx4_cleanup_counters_table(dev); - mlx4_cleanup_qp_table(dev); - mlx4_cleanup_srq_table(dev); - mlx4_cleanup_cq_table(dev); - mlx4_cmd_use_polling(dev); - mlx4_cleanup_eq_table(dev); - mlx4_cleanup_mcg_table(dev); - mlx4_cleanup_mr_table(dev); - mlx4_cleanup_xrcd_table(dev); - mlx4_cleanup_pd_table(dev); - - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_STRUCTS_ONLY); - - iounmap(priv->kar); - mlx4_uar_free(dev, &priv->driver_uar); - mlx4_cleanup_uar_table(dev); - if (!mlx4_is_slave(dev)) - mlx4_clear_steering(dev); - mlx4_free_eq_table(dev); - if (mlx4_is_master(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_close_hca(dev); - if (mlx4_is_slave(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_cmd_cleanup(dev); - - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - if (dev->flags & MLX4_FLAG_SRIOV) { - mlx4_warn(dev, "Disabling SR-IOV\n"); - pci_disable_sriov(pdev); - } - - if (!mlx4_is_slave(dev)) - mlx4_free_ownership(dev); - - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - - kfree(priv); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } -} - -static int restore_current_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *types, - enum mlx4_port_type *poss_types) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err, i; - - mlx4_stop_sense(dev); - mutex_lock(&priv->port_mutex); - for (i = 0; i < dev->caps.num_ports; i++) - dev->caps.possible_type[i + 1] = poss_types[i]; - err = mlx4_change_port_types(dev, types); - mlx4_start_sense(dev); - mutex_unlock(&priv->port_mutex); - return err; -} - -int mlx4_restart_one(struct pci_dev *pdev) -{ - struct mlx4_dev *dev = pci_get_drvdata(pdev); - struct mlx4_priv *priv = mlx4_priv(dev); - enum mlx4_port_type curr_type[MLX4_MAX_PORTS]; - enum mlx4_port_type poss_type[MLX4_MAX_PORTS]; - int pci_dev_data, err, i; - - pci_dev_data = priv->pci_dev_data; - for (i = 0; i < dev->caps.num_ports; i++) { - curr_type[i] = dev->caps.port_type[i + 1]; - poss_type[i] = dev->caps.possible_type[i + 1]; - } - - mlx4_remove_one(pdev); - err = __mlx4_init_one(pdev, pci_dev_data); - if (err) - return err; - - dev = pci_get_drvdata(pdev); - err = restore_current_port_types(dev, curr_type, poss_type); - if (err) - mlx4_err(dev, "mlx4_restart_one: could not restore original port types (%d)\n", - err); - return 0; -} - -static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = { - /* MT25408 "Hermon" SDR */ - { PCI_VDEVICE(MELLANOX, 0x6340), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR */ - { PCI_VDEVICE(MELLANOX, 0x634a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR */ - { PCI_VDEVICE(MELLANOX, 0x6354), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6732), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x673c), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6368), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6750), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6372), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x675a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26468 ConnectX EN 10GigE PCIe gen2*/ - { PCI_VDEVICE(MELLANOX, 0x6764), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */ - { PCI_VDEVICE(MELLANOX, 0x6746), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26478 ConnectX2 40GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x676e), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25400 Family [ConnectX-2 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1002), MLX4_PCI_DEV_IS_VF }, - /* MT27500 Family [ConnectX-3] */ - { PCI_VDEVICE(MELLANOX, 0x1003), 0 }, - /* MT27500 Family [ConnectX-3 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1004), MLX4_PCI_DEV_IS_VF }, - { PCI_VDEVICE(MELLANOX, 0x1005), 0 }, /* MT27510 Family */ - { PCI_VDEVICE(MELLANOX, 0x1006), 0 }, /* MT27511 Family */ - { PCI_VDEVICE(MELLANOX, 0x1007), 0 }, /* MT27520 Family */ - { PCI_VDEVICE(MELLANOX, 0x1008), 0 }, /* MT27521 Family */ - { PCI_VDEVICE(MELLANOX, 0x1009), 0 }, /* MT27530 Family */ - { PCI_VDEVICE(MELLANOX, 0x100a), 0 }, /* MT27531 Family */ - { PCI_VDEVICE(MELLANOX, 0x100b), 0 }, /* MT27540 Family */ - { PCI_VDEVICE(MELLANOX, 0x100c), 0 }, /* MT27541 Family */ - { PCI_VDEVICE(MELLANOX, 0x100d), 0 }, /* MT27550 Family */ - { PCI_VDEVICE(MELLANOX, 0x100e), 0 }, /* MT27551 Family */ - { PCI_VDEVICE(MELLANOX, 0x100f), 0 }, /* MT27560 Family */ - { PCI_VDEVICE(MELLANOX, 0x1010), 0 }, /* MT27561 Family */ - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, mlx4_pci_table); - -static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - mlx4_remove_one(pdev); - - return state == pci_channel_io_perm_failure ? - PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) -{ - int ret = __mlx4_init_one(pdev, 0); - - return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; -} - -static const struct pci_error_handlers mlx4_err_handler = { - .error_detected = mlx4_pci_err_detected, - .slot_reset = mlx4_pci_slot_reset, -}; - -static int suspend(struct pci_dev *pdev, pm_message_t state) -{ - mlx4_remove_one(pdev); - - return 0; -} - -static int resume(struct pci_dev *pdev) -{ - return __mlx4_init_one(pdev, 0); -} - -static struct pci_driver mlx4_driver = { - .name = DRV_NAME, - .id_table = mlx4_pci_table, - .probe = mlx4_init_one, - .remove = __devexit_p(mlx4_remove_one), - .suspend = suspend, - .resume = resume, - .err_handler = &mlx4_err_handler, -}; - -static int __init mlx4_verify_params(void) -{ - int status; - - status = update_defaults(&port_type_array); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&port_type_array.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - status = update_defaults(&num_vfs); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&num_vfs.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - status = update_defaults(&probe_vf); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&probe_vf.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - if (msi_x < 0) { - pr_warn("mlx4_core: bad msi_x: %d\n", msi_x); - return -1; - } - - if ((log_num_mac < 0) || (log_num_mac > 7)) { - pr_warning("mlx4_core: bad num_mac: %d\n", log_num_mac); - return -1; - } - - if (log_num_vlan != 0) - pr_warning("mlx4_core: log_num_vlan - obsolete module param, using %d\n", - MLX4_LOG_NUM_VLANS); - - if (mlx4_set_4k_mtu != -1) - pr_warning("mlx4_core: set_4k_mtu - obsolete module param\n"); - - if ((log_mtts_per_seg < 0) || (log_mtts_per_seg > 7)) { - pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg); - return -1; - } - - if (mlx4_log_num_mgm_entry_size != -1 && - (mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE || - mlx4_log_num_mgm_entry_size > MLX4_MAX_MGM_LOG_ENTRY_SIZE)) { - pr_warning("mlx4_core: mlx4_log_num_mgm_entry_size (%d) not " - "in legal range (-1 or %d..%d)\n", - mlx4_log_num_mgm_entry_size, - MLX4_MIN_MGM_LOG_ENTRY_SIZE, - MLX4_MAX_MGM_LOG_ENTRY_SIZE); - return -1; - } - - if (mod_param_profile.num_qp < 18 || mod_param_profile.num_qp > 23) { - pr_warning("mlx4_core: bad log_num_qp: %d\n", - mod_param_profile.num_qp); - return -1; - } - - if (mod_param_profile.num_srq < 10) { - pr_warning("mlx4_core: too low log_num_srq: %d\n", - mod_param_profile.num_srq); - return -1; - } - - if (mod_param_profile.num_cq < 10) { - pr_warning("mlx4_core: too low log_num_cq: %d\n", - mod_param_profile.num_cq); - return -1; - } - - if (mod_param_profile.num_mpt < 10) { - pr_warning("mlx4_core: too low log_num_mpt: %d\n", - mod_param_profile.num_mpt); - return -1; - } - - if (mod_param_profile.num_mtt_segs && - mod_param_profile.num_mtt_segs < 15) { - pr_warning("mlx4_core: too low log_num_mtt: %d\n", - mod_param_profile.num_mtt_segs); - return -1; - } - - if (mod_param_profile.num_mtt_segs > MLX4_MAX_LOG_NUM_MTT) { - pr_warning("mlx4_core: too high log_num_mtt: %d\n", - mod_param_profile.num_mtt_segs); - return -1; - } - return 0; -} - -static int __init mlx4_init(void) -{ - int ret; - - if (mlx4_verify_params()) - return -EINVAL; - - mlx4_catas_init(); - - mlx4_wq = create_singlethread_workqueue("mlx4"); - if (!mlx4_wq) - return -ENOMEM; - - if (enable_sys_tune) - sys_tune_init(); - - ret = pci_register_driver(&mlx4_driver); - if (ret < 0) - goto err; - - return 0; - -err: - if (enable_sys_tune) - sys_tune_fini(); - - destroy_workqueue(mlx4_wq); - - return ret; -} - -static void __exit mlx4_cleanup(void) -{ - if (enable_sys_tune) - sys_tune_fini(); - - pci_unregister_driver(&mlx4_driver); - destroy_workqueue(mlx4_wq); -} - -module_init_order(mlx4_init, SI_ORDER_MIDDLE); -module_exit(mlx4_cleanup); - -static int -mlx4_evhand(module_t mod, int event, void *arg) -{ - return (0); -} - -static moduledata_t mlx4_mod = { - .name = "mlx4", - .evhand = mlx4_evhand, -}; -MODULE_VERSION(mlx4, 1); -DECLARE_MODULE(mlx4, mlx4_mod, SI_SUB_OFED_PREINIT, SI_ORDER_ANY); -MODULE_DEPEND(mlx4, linuxkpi, 1, 1, 1); - diff --git a/sys/ofed/drivers/net/mlx4/mcg.c b/sys/ofed/drivers/net/mlx4/mcg.c deleted file mode 100644 index 71c1c838564c..000000000000 --- a/sys/ofed/drivers/net/mlx4/mcg.c +++ /dev/null @@ -1,1543 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/string.h> -#include <linux/etherdevice.h> - -#include <linux/mlx4/cmd.h> -#include <linux/module.h> -#include <linux/printk.h> - -#include "mlx4.h" - -int mlx4_get_mgm_entry_size(struct mlx4_dev *dev) -{ - return 1 << dev->oper_log_mgm_entry_size; -} - -int mlx4_get_qp_per_mgm(struct mlx4_dev *dev) -{ - return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2); -} - -static int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox, - u32 size, - u64 *reg_id) -{ - u64 imm; - int err = 0; - - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0, - MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - return err; - *reg_id = imm; - - return err; -} - -static int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid) -{ - int err = 0; - - err = mlx4_cmd(dev, regid, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - return err; -} - -static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) -{ - return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer, - struct mlx4_cmd_mailbox *mailbox) -{ - u32 in_mod; - - in_mod = (u32) port << 16 | steer << 1; - return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, - MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); -} - -static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - u16 *hash, u8 op_mod) -{ - u64 imm; - int err; - - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, - MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - if (!err) - *hash = imm; - - return err; -} - -static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_promisc_qp *pqp; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { - if (pqp->qpn == qpn) - return pqp; - } - /* not found */ - return NULL; -} - -/* - * Add new entry to steering data structure. - * All promisc QPs should be added as well - */ -static int new_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - struct mlx4_steer_index *new_entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp = NULL; - u32 prot; - int err; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); - if (!new_entry) - return -ENOMEM; - - INIT_LIST_HEAD(&new_entry->duplicates); - new_entry->index = index; - list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); - - /* If the given qpn is also a promisc qp, - * it should be inserted to duplicates list - */ - pqp = get_promisc_qp(dev, port, steer, qpn); - if (pqp) { - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) { - err = -ENOMEM; - goto out_alloc; - } - dqp->qpn = qpn; - list_add_tail(&dqp->list, &new_entry->duplicates); - } - - /* if no promisc qps for this vep, we are done */ - if (list_empty(&s_steer->promisc_qps[steer])) - return 0; - - /* now need to add all the promisc qps to the new - * steering entry, as they should also receive the packets - * destined to this address */ - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - goto out_alloc; - } - mgm = mailbox->buf; - - err = mlx4_READ_ENTRY(dev, index, mailbox); - if (err) - goto out_mailbox; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - prot = be32_to_cpu(mgm->members_count) >> 30; - list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { - /* don't add already existing qpn */ - if (pqp->qpn == qpn) - continue; - if (members_count == dev->caps.num_qp_per_mgm) { - /* out of space */ - err = -ENOMEM; - goto out_mailbox; - } - - /* add the qpn */ - mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); - } - /* update the qps count and update the entry with all the promisc qps*/ - mgm->members_count = cpu_to_be32(members_count | (prot << 30)); - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); - if (!err) - return 0; -out_alloc: - if (dqp) { - list_del(&dqp->list); - kfree(dqp); - } - list_del(&new_entry->list); - kfree(new_entry); - return err; -} - -/* update the data structures with existing steering entry */ -static int existing_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *tmp_entry, *entry = NULL; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - pqp = get_promisc_qp(dev, port, steer, qpn); - if (!pqp) - return 0; /* nothing to do */ - - list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { - if (tmp_entry->index == index) { - entry = tmp_entry; - break; - } - } - if (unlikely(!entry)) { - mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); - return -EINVAL; - } - - /* the given qpn is listed as a promisc qpn - * we need to add it as a duplicate to this entry - * for future references */ - list_for_each_entry(dqp, &entry->duplicates, list) { - if (qpn == dqp->qpn) - return 0; /* qp is already duplicated */ - } - - /* add the qp as a duplicate on this index */ - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) - return -ENOMEM; - dqp->qpn = qpn; - list_add_tail(&dqp->list, &entry->duplicates); - - return 0; -} - -/* Check whether a qpn is a duplicate on steering entry - * If so, it should not be removed from mgm */ -static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *tmp_entry, *entry = NULL; - struct mlx4_promisc_qp *dqp, *tmp_dqp; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - /* if qp is not promisc, it cannot be duplicated */ - if (!get_promisc_qp(dev, port, steer, qpn)) - return false; - - /* The qp is promisc qp so it is a duplicate on this index - * Find the index entry, and remove the duplicate */ - list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { - if (tmp_entry->index == index) { - entry = tmp_entry; - break; - } - } - if (unlikely(!entry)) { - mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); - return false; - } - list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { - if (dqp->qpn == qpn) { - list_del(&dqp->list); - kfree(dqp); - } - } - return true; -} - -/* - * returns true if all the QPs != tqpn contained in this entry - * are Promisc QPs. return false otherwise. - */ -static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 tqpn, u32 *members_count) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 m_count; - bool ret = false; - int i; - - if (port < 1 || port > dev->caps.num_ports) - return false; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return false; - mgm = mailbox->buf; - - if (mlx4_READ_ENTRY(dev, index, mailbox)) - goto out; - m_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (members_count) - *members_count = m_count; - - for (i = 0; i < m_count; i++) { - u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; - if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { - /* the qp is not promisc, the entry can't be removed */ - goto out; - } - } - ret = true; -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} - -/* IF a steering entry contains only promisc QPs, it can be removed. */ -static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 tqpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *entry = NULL, *tmp_entry; - u32 members_count; - bool ret = false; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count)) - goto out; - - /* All the qps currently registered for this entry are promiscuous, - * Checking for duplicates */ - ret = true; - list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { - if (entry->index == index) { - if (list_empty(&entry->duplicates) || members_count == 1) { - struct mlx4_promisc_qp *pqp, *tmp_pqp; - /* - * If there is only 1 entry in duplicates than - * this is the QP we want to delete, going over - * the list and deleting the entry. - */ - list_del(&entry->list); - list_for_each_entry_safe(pqp, tmp_pqp, - &entry->duplicates, - list) { - list_del(&pqp->list); - kfree(pqp); - } - kfree(entry); - } else { - /* This entry contains duplicates so it shouldn't be removed */ - ret = false; - goto out; - } - } - } - -out: - return ret; -} - -static int add_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - u32 members_count; - u32 prot; - int i; - bool found; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - mutex_lock(&priv->mcg_table.mutex); - - if (get_promisc_qp(dev, port, steer, qpn)) { - err = 0; /* Noting to do, already exists */ - goto out_mutex; - } - - pqp = kmalloc(sizeof *pqp, GFP_KERNEL); - if (!pqp) { - err = -ENOMEM; - goto out_mutex; - } - pqp->qpn = qpn; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - goto out_alloc; - } - mgm = mailbox->buf; - - if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { - /* the promisc qp needs to be added for each one of the steering - * entries, if it already exists, needs to be added as a duplicate - * for this entry */ - list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - prot = be32_to_cpu(mgm->members_count) >> 30; - found = false; - for (i = 0; i < members_count; i++) { - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { - /* Entry already exists, add to duplicates */ - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) { - err = -ENOMEM; - goto out_mailbox; - } - dqp->qpn = qpn; - list_add_tail(&dqp->list, &entry->duplicates); - found = true; - } - } - if (!found) { - /* Need to add the qpn to mgm */ - if (members_count == dev->caps.num_qp_per_mgm) { - /* entry is full */ - err = -ENOMEM; - goto out_mailbox; - } - mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (prot << 30)); - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - } - } - } - - /* add the new qpn to list of promisc qps */ - list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); - /* now need to add all the promisc qps to default entry */ - memset(mgm, 0, sizeof *mgm); - members_count = 0; - list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { - if (members_count == dev->caps.num_qp_per_mgm) { - /* entry is full */ - err = -ENOMEM; - goto out_list; - } - mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); - } - mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); - - err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); - if (err) - goto out_list; - - mlx4_free_cmd_mailbox(dev, mailbox); - mutex_unlock(&priv->mcg_table.mutex); - return 0; - -out_list: - list_del(&pqp->list); -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); -out_alloc: - kfree(pqp); -out_mutex: - mutex_unlock(&priv->mcg_table.mutex); - return err; -} - -static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, u32 qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry, *tmp_entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - u32 members_count; - bool found; - bool back_to_list = false; - int i, loc = -1; - int err; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - mutex_lock(&priv->mcg_table.mutex); - - pqp = get_promisc_qp(dev, port, steer, qpn); - if (unlikely(!pqp)) { - mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); - /* nothing to do */ - err = 0; - goto out_mutex; - } - - /*remove from list of promisc qps */ - list_del(&pqp->list); - - /* set the default entry not to include the removed one */ - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - back_to_list = true; - goto out_list; - } - mgm = mailbox->buf; - memset(mgm, 0, sizeof *mgm); - members_count = 0; - list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) - mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); - - err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); - if (err) - goto out_mailbox; - - if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { - /* remove the qp from all the steering entries*/ - list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { - found = false; - list_for_each_entry(dqp, &entry->duplicates, list) { - if (dqp->qpn == qpn) { - found = true; - break; - } - } - if (found) { - /* a duplicate, no need to change the mgm, - * only update the duplicates list */ - list_del(&dqp->list); - kfree(dqp); - } else { - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (!members_count) { - mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0." - " deleting entry...\n", qpn, entry->index); - list_del(&entry->list); - kfree(entry); - continue; - } - - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { - loc = i; - break; - } - - if (loc < 0) { - mlx4_err(dev, "QP %06x wasn't found in entry %d\n", - qpn, entry->index); - err = -EINVAL; - goto out_mailbox; - } - - /* copy the last QP in this MGM over removed QP */ - mgm->qp[loc] = mgm->qp[members_count - 1]; - mgm->qp[members_count - 1] = 0; - mgm->members_count = cpu_to_be32(--members_count | - (MLX4_PROT_ETH << 30)); - - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - } - } - } - -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); -out_list: - if (back_to_list) - list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); - else - kfree(pqp); -out_mutex: - mutex_unlock(&priv->mcg_table.mutex); - return err; -} - -/* - * Caller must hold MCG table semaphore. gid and mgm parameters must - * be properly aligned for command interface. - * - * Returns 0 unless a firmware command error occurs. - * - * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 - * and *mgm holds MGM entry. - * - * if GID is found in AMGM, *index = index in AMGM, *prev = index of - * previous entry in hash chain and *mgm holds AMGM entry. - * - * If no AMGM exists for given gid, *index = -1, *prev = index of last - * entry in hash chain and *mgm holds end of hash chain. - */ -static int find_entry(struct mlx4_dev *dev, u8 port, - u8 *gid, enum mlx4_protocol prot, - struct mlx4_cmd_mailbox *mgm_mailbox, - int *prev, int *index) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm = mgm_mailbox->buf; - u8 *mgid; - int err; - u16 hash; - u8 op_mod = (prot == MLX4_PROT_ETH) ? - !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return -ENOMEM; - mgid = mailbox->buf; - - memcpy(mgid, gid, 16); - - err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - return err; - - if (0) { - mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n", - GID_PRINT_ARGS(gid), hash); - } - - *index = hash; - *prev = -1; - - do { - err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); - if (err) - return err; - - if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { - if (*index != hash) { - mlx4_err(dev, "Found zero MGID in AMGM.\n"); - err = -EINVAL; - } - return err; - } - - if (!memcmp(mgm->gid, gid, 16) && - be32_to_cpu(mgm->members_count) >> 30 == prot) - return err; - - *prev = *index; - *index = be32_to_cpu(mgm->next_gid_index) >> 6; - } while (*index); - - *index = -1; - return err; -} - -static const u8 __promisc_mode[] = { - [MLX4_FS_REGULAR] = 0x0, - [MLX4_FS_ALL_DEFAULT] = 0x1, - [MLX4_FS_MC_DEFAULT] = 0x3, - [MLX4_FS_UC_SNIFFER] = 0x4, - [MLX4_FS_MC_SNIFFER] = 0x5, -}; - -int map_sw_to_hw_steering_mode(struct mlx4_dev *dev, - enum mlx4_net_trans_promisc_mode flow_type) -{ - if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) { - mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); - return -EINVAL; - } - return __promisc_mode[flow_type]; -} -EXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode); - -static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, - struct mlx4_net_trans_rule_hw_ctrl *hw) -{ - u8 flags = 0; - - flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; - flags |= ctrl->exclusive ? (1 << 2) : 0; - flags |= ctrl->allow_loopback ? (1 << 3) : 0; - - hw->flags = flags; - hw->type = __promisc_mode[ctrl->promisc_mode]; - hw->prio = cpu_to_be16(ctrl->priority); - hw->port = ctrl->port; - hw->qpn = cpu_to_be32(ctrl->qpn); -} - -const u16 __sw_id_hw[] = { - [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, - [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, - [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, - [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, - [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, - [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 -}; - -int map_sw_to_hw_steering_id(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - return __sw_id_hw[id]; -} -EXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id); - -static const int __rule_hw_sz[] = { - [MLX4_NET_TRANS_RULE_ID_ETH] = - sizeof(struct mlx4_net_trans_rule_hw_eth), - [MLX4_NET_TRANS_RULE_ID_IB] = - sizeof(struct mlx4_net_trans_rule_hw_ib), - [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, - [MLX4_NET_TRANS_RULE_ID_IPV4] = - sizeof(struct mlx4_net_trans_rule_hw_ipv4), - [MLX4_NET_TRANS_RULE_ID_TCP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), - [MLX4_NET_TRANS_RULE_ID_UDP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) -}; - -int hw_rule_sz(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - - return __rule_hw_sz[id]; -} -EXPORT_SYMBOL_GPL(hw_rule_sz); - -static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, - struct _rule_hw *rule_hw) -{ - if (hw_rule_sz(dev, spec->id) < 0) - return -EINVAL; - memset(rule_hw, 0, hw_rule_sz(dev, spec->id)); - rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); - rule_hw->size = hw_rule_sz(dev, spec->id) >> 2; - - switch (spec->id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN); - memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk, - ETH_ALEN); - memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN); - memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk, - ETH_ALEN); - if (spec->eth.ether_type_enable) { - rule_hw->eth.ether_type_enable = 1; - rule_hw->eth.ether_type = spec->eth.ether_type; - } - rule_hw->eth.vlan_tag = spec->eth.vlan_id; - rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; - break; - - case MLX4_NET_TRANS_RULE_ID_IB: - rule_hw->ib.l3_qpn = spec->ib.l3_qpn; - rule_hw->ib.qpn_mask = spec->ib.qpn_msk; - memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16); - memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV6: - return -EOPNOTSUPP; - - case MLX4_NET_TRANS_RULE_ID_IPV4: - rule_hw->ipv4.src_ip = spec->ipv4.src_ip; - rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk; - rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip; - rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk; - break; - - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port; - rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk; - rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port; - rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk; - break; - - default: - return -EINVAL; - } - - return __rule_hw_sz[spec->id]; -} - -static void mlx4_err_rule(struct mlx4_dev *dev, char *str, - struct mlx4_net_trans_rule *rule) -{ -#define BUF_SIZE 256 - struct mlx4_spec_list *cur; - char buf[BUF_SIZE]; - int len = 0; - - mlx4_err(dev, "%s", str); - len += snprintf(buf + len, BUF_SIZE - len, - "port = %d prio = 0x%x qp = 0x%x ", - rule->port, rule->priority, rule->qpn); - - list_for_each_entry(cur, &rule->list, list) { - switch (cur->id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - len += snprintf(buf + len, BUF_SIZE - len, - "dmac = %pM ", &cur->eth.dst_mac); - if (cur->eth.ether_type) - len += snprintf(buf + len, BUF_SIZE - len, - "ethertype = 0x%x ", - be16_to_cpu(cur->eth.ether_type)); - if (cur->eth.vlan_id) - len += snprintf(buf + len, BUF_SIZE - len, - "vlan-id = %d ", - be16_to_cpu(cur->eth.vlan_id)); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV4: - if (cur->ipv4.src_ip) - len += snprintf(buf + len, BUF_SIZE - len, - "src-ip = %pI4 ", - &cur->ipv4.src_ip); - if (cur->ipv4.dst_ip) - len += snprintf(buf + len, BUF_SIZE - len, - "dst-ip = %pI4 ", - &cur->ipv4.dst_ip); - break; - - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - if (cur->tcp_udp.src_port) - len += snprintf(buf + len, BUF_SIZE - len, - "src-port = %d ", - be16_to_cpu(cur->tcp_udp.src_port)); - if (cur->tcp_udp.dst_port) - len += snprintf(buf + len, BUF_SIZE - len, - "dst-port = %d ", - be16_to_cpu(cur->tcp_udp.dst_port)); - break; - - case MLX4_NET_TRANS_RULE_ID_IB: - len += snprintf(buf + len, BUF_SIZE - len, - "dst-gid = "GID_PRINT_FMT"\n", - GID_PRINT_ARGS(cur->ib.dst_gid)); - len += snprintf(buf + len, BUF_SIZE - len, - "dst-gid-mask = "GID_PRINT_FMT"\n", - GID_PRINT_ARGS(cur->ib.dst_gid_msk)); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV6: - break; - - default: - break; - } - } - len += snprintf(buf + len, BUF_SIZE - len, "\n"); - mlx4_err(dev, "%s", buf); - - if (len >= BUF_SIZE) - mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n"); -} - -int mlx4_flow_attach(struct mlx4_dev *dev, - struct mlx4_net_trans_rule *rule, u64 *reg_id) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_spec_list *cur; - u32 size = 0; - int ret; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl)); - trans_rule_ctrl_to_hw(rule, mailbox->buf); - - size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); - - list_for_each_entry(cur, &rule->list, list) { - ret = parse_trans_rule(dev, cur, mailbox->buf + size); - if (ret < 0) { - mlx4_free_cmd_mailbox(dev, mailbox); - return -EINVAL; - } - size += ret; - } - - ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id); - if (ret == -ENOMEM) - mlx4_err_rule(dev, - "mcg table is full. Fail to register network rule.\n", - rule); - else if (ret) - mlx4_err_rule(dev, "Fail to register network rule.\n", rule); - - mlx4_free_cmd_mailbox(dev, mailbox); - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_flow_attach); - -int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id) -{ - int err; - - err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id); - if (err) - mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n", - (unsigned long long)reg_id); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_flow_detach); - -int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn) -{ - int err; - u64 in_param; - - in_param = ((u64) min_range_qpn) << 32; - in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF; - - err = mlx4_cmd(dev, in_param, 0, 0, - MLX4_FLOW_STEERING_IB_UC_QP_RANGE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE); - -int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type steer) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - int index, prev; - int link = 0; - int i; - int err; - u8 port = gid[5]; - u8 new_entry = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - mgm = mailbox->buf; - - mutex_lock(&priv->mcg_table.mutex); - err = find_entry(dev, port, gid, prot, - mailbox, &prev, &index); - if (err) - goto out; - - if (index != -1) { - if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { - new_entry = 1; - memcpy(mgm->gid, gid, 16); - } - } else { - link = 1; - - index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); - if (index == -1) { - mlx4_err(dev, "No AMGM entries left\n"); - err = -ENOMEM; - goto out; - } - index += dev->caps.num_mgms; - - new_entry = 1; - memset(mgm, 0, sizeof *mgm); - memcpy(mgm->gid, gid, 16); - } - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (members_count == dev->caps.num_qp_per_mgm) { - mlx4_err(dev, "MGM at index %x is full.\n", index); - err = -ENOMEM; - goto out; - } - - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { - mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); - err = 0; - goto out; - } - - mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | - (!!mlx4_blck_lb << MGM_BLCK_LB_BIT)); - - mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); - - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - if (err) - goto out; - - /* if !link, still add the new entry. */ - if (!link) - goto skip_link; - - err = mlx4_READ_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - mgm->next_gid_index = cpu_to_be32(index << 6); - - err = mlx4_WRITE_ENTRY(dev, prev, mailbox); - if (err) - goto out; - -skip_link: - if (prot == MLX4_PROT_ETH) { - /* manage the steering entry for promisc mode */ - if (new_entry) - new_steering_entry(dev, port, steer, index, qp->qpn); - else - existing_steering_entry(dev, port, steer, - index, qp->qpn); - } - -out: - if (err && link && index != -1) { - if (index < dev->caps.num_mgms) - mlx4_warn(dev, "Got AMGM index %d < %d", - index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms, MLX4_USE_RR); - } - mutex_unlock(&priv->mcg_table.mutex); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type steer) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - int prev, index; - int i, loc = -1; - int err; - u8 port = gid[5]; - bool removed_entry = false; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - mgm = mailbox->buf; - - mutex_lock(&priv->mcg_table.mutex); - - err = find_entry(dev, port, gid, prot, - mailbox, &prev, &index); - if (err) - goto out; - - if (index == -1) { - mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n", - GID_PRINT_ARGS(gid)); - err = -EINVAL; - goto out; - } - - /* - if this QP is also a promisc QP, it shouldn't be removed only if - at least one none promisc QP is also attached to this MCG - */ - if (prot == MLX4_PROT_ETH && - check_duplicate_entry(dev, port, steer, index, qp->qpn) && - !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) - goto out; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { - loc = i; - break; - } - - if (loc == -1) { - mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); - err = -EINVAL; - goto out; - } - - /* copy the last QP in this MGM over removed QP */ - mgm->qp[loc] = mgm->qp[members_count - 1]; - mgm->qp[members_count - 1] = 0; - mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); - - if (prot == MLX4_PROT_ETH) - removed_entry = can_remove_steering_entry(dev, port, steer, - index, qp->qpn); - if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - goto out; - } - - /* We are going to delete the entry, members count should be 0 */ - mgm->members_count = cpu_to_be32((u32) prot << 30); - - if (prev == -1) { - /* Remove entry from MGM */ - int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; - if (amgm_index) { - err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); - if (err) - goto out; - } else - memset(mgm->gid, 0, 16); - - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - if (err) - goto out; - - if (amgm_index) { - if (amgm_index < dev->caps.num_mgms) - mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", - index, amgm_index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - amgm_index - dev->caps.num_mgms, MLX4_USE_RR); - } - } else { - /* Remove entry from AMGM */ - int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; - err = mlx4_READ_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); - - err = mlx4_WRITE_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - if (index < dev->caps.num_mgms) - mlx4_warn(dev, "entry %d had next AMGM index %d < %d", - prev, index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms, MLX4_USE_RR); - } - -out: - mutex_unlock(&priv->mcg_table.mutex); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 attach, u8 block_loopback, - enum mlx4_protocol prot) -{ - struct mlx4_cmd_mailbox *mailbox; - int err = 0; - int qpn; - - if (!mlx4_is_mfunc(dev)) - return -EBADF; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, gid, 16); - qpn = qp->qpn; - qpn |= (prot << 28); - if (attach && block_loopback) - qpn |= (1 << 31); - - err = mlx4_cmd(dev, mailbox->dma, qpn, attach, - MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 port, - int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id) -{ - struct mlx4_spec_list spec = { {NULL} }; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - struct mlx4_net_trans_rule rule = { - .queue_mode = MLX4_NET_TRANS_Q_FIFO, - .exclusive = 0, - .promisc_mode = MLX4_FS_REGULAR, - .priority = MLX4_DOMAIN_NIC, - }; - - rule.allow_loopback = !block_mcast_loopback; - rule.port = port; - rule.qpn = qp->qpn; - INIT_LIST_HEAD(&rule.list); - - switch (prot) { - case MLX4_PROT_ETH: - spec.id = MLX4_NET_TRANS_RULE_ID_ETH; - memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN); - memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - break; - - case MLX4_PROT_IB_IPV6: - spec.id = MLX4_NET_TRANS_RULE_ID_IB; - memcpy(spec.ib.dst_gid, gid, 16); - memset(&spec.ib.dst_gid_msk, 0xff, 16); - break; - default: - return -EINVAL; - } - list_add_tail(&spec.list, &rule.list); - - return mlx4_flow_attach(dev, &rule, reg_id); -} - -int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - u8 port, int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id) -{ - enum mlx4_steer_type steer; - steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_A0: - if (prot == MLX4_PROT_ETH) - return 0; - - case MLX4_STEERING_MODE_B0: - if (prot == MLX4_PROT_ETH) - gid[7] |= (steer << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 1, - block_mcast_loopback, prot); - return mlx4_qp_attach_common(dev, qp, gid, - block_mcast_loopback, prot, - MLX4_MC_STEER); - - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, - block_mcast_loopback, - prot, reg_id); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(mlx4_multicast_attach); - -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, u64 reg_id) -{ - enum mlx4_steer_type steer; - steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_A0: - if (prot == MLX4_PROT_ETH) - return 0; - - case MLX4_STEERING_MODE_B0: - if (prot == MLX4_PROT_ETH) - gid[7] |= (steer << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); - - return mlx4_qp_detach_common(dev, qp, gid, prot, - MLX4_MC_STEER); - - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_flow_detach(dev, reg_id); - - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(mlx4_multicast_detach); - -int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, - u32 qpn, enum mlx4_net_trans_promisc_mode mode) -{ - struct mlx4_net_trans_rule rule; - u64 *regid_p; - - switch (mode) { - case MLX4_FS_ALL_DEFAULT: - regid_p = &dev->regid_promisc_array[port]; - break; - case MLX4_FS_MC_DEFAULT: - regid_p = &dev->regid_allmulti_array[port]; - break; - default: - return -1; - } - - if (*regid_p != 0) - return -1; - - rule.promisc_mode = mode; - rule.port = port; - rule.qpn = qpn; - INIT_LIST_HEAD(&rule.list); - mlx4_err(dev, "going promisc on %x\n", port); - - return mlx4_flow_attach(dev, &rule, regid_p); -} -EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add); - -int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, - enum mlx4_net_trans_promisc_mode mode) -{ - int ret; - u64 *regid_p; - - switch (mode) { - case MLX4_FS_ALL_DEFAULT: - regid_p = &dev->regid_promisc_array[port]; - break; - case MLX4_FS_MC_DEFAULT: - regid_p = &dev->regid_allmulti_array[port]; - break; - default: - return -1; - } - - if (*regid_p == 0) - return -1; - - ret = mlx4_flow_detach(dev, *regid_p); - if (ret == 0) - *regid_p = 0; - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove); - -int mlx4_unicast_attach(struct mlx4_dev *dev, - struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot) -{ - if (prot == MLX4_PROT_ETH) - gid[7] |= (MLX4_UC_STEER << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 1, - block_mcast_loopback, prot); - - return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, - prot, MLX4_UC_STEER); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_attach); - -int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], enum mlx4_protocol prot) -{ - if (prot == MLX4_PROT_ETH) - gid[7] |= (MLX4_UC_STEER << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); - - return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_detach); - -int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u32 qpn = (u32) vhcr->in_param & 0xffffffff; - u8 port = vhcr->in_param >> 62; - enum mlx4_steer_type steer = vhcr->in_modifier; - - /* Promiscuous unicast is not allowed in mfunc for VFs */ - if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER)) - return 0; - - if (vhcr->op_modifier) - return add_promisc_qp(dev, port, steer, qpn); - else - return remove_promisc_qp(dev, port, steer, qpn); -} - -static int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, - enum mlx4_steer_type steer, u8 add, u8 port) -{ - return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, - MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); - - return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); - -int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); - - return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); - -int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); - - return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); - -int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); - - return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); - -int mlx4_init_mcg_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - - /* No need for mcg_table when fw managed the mcg table*/ - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) - return 0; - err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, - dev->caps.num_amgms - 1, 0, 0); - if (err) - return err; - - mutex_init(&priv->mcg_table.mutex); - - return 0; -} - -void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) -{ - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/mlx4.h b/sys/ofed/drivers/net/mlx4/mlx4.h deleted file mode 100644 index e23e461fd022..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4.h +++ /dev/null @@ -1,1328 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef MLX4_H -#define MLX4_H - -#include <linux/mutex.h> -#include <linux/radix-tree.h> -#include <linux/rbtree.h> -#include <linux/timer.h> -#include <linux/semaphore.h> -#include <linux/workqueue.h> -#include <linux/device.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/driver.h> -#include <linux/mlx4/doorbell.h> -#include <linux/mlx4/cmd.h> - -#define DRV_NAME "mlx4_core" -#define PFX DRV_NAME ": " -#define DRV_VERSION "2.1.6" -#define DRV_RELDATE __DATE__ - -#define DRV_STACK_NAME "Linux-MLNX_OFED" -#define DRV_STACK_VERSION "2.1" -#define DRV_NAME_FOR_FW DRV_STACK_NAME","DRV_STACK_VERSION - -#define MLX4_FS_UDP_UC_EN (1 << 1) -#define MLX4_FS_TCP_UC_EN (1 << 2) -#define MLX4_FS_NUM_OF_L2_ADDR 8 -#define MLX4_FS_MGM_LOG_ENTRY_SIZE 7 -#define MLX4_FS_NUM_MCG (1 << 17) - -struct mlx4_set_port_prio2tc_context { - u8 prio2tc[4]; -}; - -struct mlx4_port_scheduler_tc_cfg_be { - __be16 pg; - __be16 bw_precentage; - __be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */ - __be16 max_bw_value; -}; - -struct mlx4_set_port_scheduler_context { - struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; -}; - -enum { - MLX4_HCR_BASE = 0x80680, - MLX4_HCR_SIZE = 0x0001c, - MLX4_CLR_INT_SIZE = 0x00008, - MLX4_SLAVE_COMM_BASE = 0x0, - MLX4_COMM_PAGESIZE = 0x1000, - MLX4_CLOCK_SIZE = 0x00008 -}; - -enum { - MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE = 10, - MLX4_MIN_MGM_LOG_ENTRY_SIZE = 7, - MLX4_MAX_MGM_LOG_ENTRY_SIZE = 12, - MLX4_MAX_QP_PER_MGM = 4 * ((1 << MLX4_MAX_MGM_LOG_ENTRY_SIZE)/16 - 2), -}; - -enum { - MLX4_NUM_PDS = 1 << 15 -}; - -enum { - MLX4_CMPT_TYPE_QP = 0, - MLX4_CMPT_TYPE_SRQ = 1, - MLX4_CMPT_TYPE_CQ = 2, - MLX4_CMPT_TYPE_EQ = 3, - MLX4_CMPT_NUM_TYPE -}; - -enum { - MLX4_CMPT_SHIFT = 24, - MLX4_NUM_CMPTS = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT -}; - -enum mlx4_mpt_state { - MLX4_MPT_DISABLED = 0, - MLX4_MPT_EN_HW, - MLX4_MPT_EN_SW -}; - -#define MLX4_COMM_TIME 10000 -enum { - MLX4_COMM_CMD_RESET, - MLX4_COMM_CMD_VHCR0, - MLX4_COMM_CMD_VHCR1, - MLX4_COMM_CMD_VHCR2, - MLX4_COMM_CMD_VHCR_EN, - MLX4_COMM_CMD_VHCR_POST, - MLX4_COMM_CMD_FLR = 254 -}; - -/*The flag indicates that the slave should delay the RESET cmd*/ -#define MLX4_DELAY_RESET_SLAVE 0xbbbbbbb -/*indicates how many retries will be done if we are in the middle of FLR*/ -#define NUM_OF_RESET_RETRIES 10 -#define SLEEP_TIME_IN_RESET (2 * 1000) -enum mlx4_resource { - RES_QP, - RES_CQ, - RES_SRQ, - RES_XRCD, - RES_MPT, - RES_MTT, - RES_MAC, - RES_VLAN, - RES_NPORT_ID, - RES_COUNTER, - RES_FS_RULE, - RES_EQ, - MLX4_NUM_OF_RESOURCE_TYPE -}; - -enum mlx4_alloc_mode { - RES_OP_RESERVE, - RES_OP_RESERVE_AND_MAP, - RES_OP_MAP_ICM, -}; - -enum mlx4_res_tracker_free_type { - RES_TR_FREE_ALL, - RES_TR_FREE_SLAVES_ONLY, - RES_TR_FREE_STRUCTS_ONLY, -}; - -/* - *Virtual HCR structures. - * mlx4_vhcr is the sw representation, in machine endianness - * - * mlx4_vhcr_cmd is the formalized structure, the one that is passed - * to FW to go through communication channel. - * It is big endian, and has the same structure as the physical HCR - * used by command interface - */ -struct mlx4_vhcr { - u64 in_param; - u64 out_param; - u32 in_modifier; - u32 errno; - u16 op; - u16 token; - u8 op_modifier; - u8 e_bit; -}; - -struct mlx4_vhcr_cmd { - __be64 in_param; - __be32 in_modifier; - u32 reserved1; - __be64 out_param; - __be16 token; - u16 reserved; - u8 status; - u8 flags; - __be16 opcode; -} __packed; - -struct mlx4_cmd_info { - u16 opcode; - bool has_inbox; - bool has_outbox; - bool out_is_imm; - bool encode_slave_id; - bool skip_err_print; - int (*verify)(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox); - int (*wrapper)(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -}; - -enum { - MLX4_DEBUG_MASK_CMD_TIME = 0x100, -}; - -#ifdef CONFIG_MLX4_DEBUG -extern int mlx4_debug_level; -#else /* CONFIG_MLX4_DEBUG */ -#define mlx4_debug_level (0) -#endif /* CONFIG_MLX4_DEBUG */ - -#define mlx4_dbg(mdev, format, arg...) \ -do { \ - if (mlx4_debug_level) \ - dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ##arg); \ -} while (0) - -#define mlx4_err(mdev, format, arg...) \ - dev_err(&mdev->pdev->dev, format, ##arg) -#define mlx4_info(mdev, format, arg...) \ - dev_info(&mdev->pdev->dev, format, ##arg) -#define mlx4_warn(mdev, format, arg...) \ - dev_warn(&mdev->pdev->dev, format, ##arg) - -extern int mlx4_log_num_mgm_entry_size; -extern int log_mtts_per_seg; -extern int mlx4_blck_lb; -extern int mlx4_set_4k_mtu; - -#define MLX4_MAX_NUM_SLAVES (MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF) -#define ALL_SLAVES 0xff - -struct mlx4_bitmap { - u32 last; - u32 top; - u32 max; - u32 reserved_top; - u32 mask; - u32 avail; - spinlock_t lock; - unsigned long *table; -}; - -struct mlx4_buddy { - unsigned long **bits; - unsigned int *num_free; - u32 max_order; - spinlock_t lock; -}; - -struct mlx4_icm; - -struct mlx4_icm_table { - u64 virt; - int num_icm; - u32 num_obj; - int obj_size; - int lowmem; - int coherent; - struct mutex mutex; - struct mlx4_icm **icm; -}; - -#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28) -#define MLX4_MPT_FLAG_FREE (0x3UL << 28) -#define MLX4_MPT_FLAG_MIO (1 << 17) -#define MLX4_MPT_FLAG_BIND_ENABLE (1 << 15) -#define MLX4_MPT_FLAG_PHYSICAL (1 << 9) -#define MLX4_MPT_FLAG_REGION (1 << 8) - -#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) -#define MLX4_MPT_PD_FLAG_RAE (1 << 28) -#define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) - -#define MLX4_MPT_QP_FLAG_BOUND_QP (1 << 7) - -#define MLX4_MPT_STATUS_SW 0xF0 -#define MLX4_MPT_STATUS_HW 0x00 - -/* - * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. - */ -struct mlx4_mpt_entry { - __be32 flags; - __be32 qpn; - __be32 key; - __be32 pd_flags; - __be64 start; - __be64 length; - __be32 lkey; - __be32 win_cnt; - u8 reserved1[3]; - u8 mtt_rep; - __be64 mtt_addr; - __be32 mtt_sz; - __be32 entity_size; - __be32 first_byte_offset; -} __packed; - -/* - * Must be packed because start is 64 bits but only aligned to 32 bits. - */ -struct mlx4_eq_context { - __be32 flags; - u16 reserved1[3]; - __be16 page_offset; - u8 log_eq_size; - u8 reserved2[4]; - u8 eq_period; - u8 reserved3; - u8 eq_max_count; - u8 reserved4[3]; - u8 intr; - u8 log_page_size; - u8 reserved5[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - u32 reserved6[2]; - __be32 consumer_index; - __be32 producer_index; - u32 reserved7[4]; -}; - -struct mlx4_cq_context { - __be32 flags; - u16 reserved1[3]; - __be16 page_offset; - __be32 logsize_usrpage; - __be16 cq_period; - __be16 cq_max_count; - u8 reserved2[3]; - u8 comp_eqn; - u8 log_page_size; - u8 reserved3[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - __be32 last_notified_index; - __be32 solicit_producer_index; - __be32 consumer_index; - __be32 producer_index; - u32 reserved4[2]; - __be64 db_rec_addr; -}; - -struct mlx4_srq_context { - __be32 state_logsize_srqn; - u8 logstride; - u8 reserved1; - __be16 xrcd; - __be32 pg_offset_cqn; - u32 reserved2; - u8 log_page_size; - u8 reserved3[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - __be32 pd; - __be16 limit_watermark; - __be16 wqe_cnt; - u16 reserved4; - __be16 wqe_counter; - u32 reserved5; - __be64 db_rec_addr; -}; - -struct mlx4_eq { - struct mlx4_dev *dev; - void __iomem *doorbell; - int eqn; - u32 cons_index; - u16 irq; - u16 have_irq; - int nent; - struct mlx4_buf_list *page_list; - struct mlx4_mtt mtt; -}; - -struct mlx4_slave_eqe { - u8 type; - u8 port; - u32 param; -}; - -struct mlx4_slave_event_eq_info { - int eqn; - u16 token; -}; - -struct mlx4_profile { - int num_qp; - int rdmarc_per_qp; - int num_srq; - int num_cq; - int num_mcg; - int num_mpt; - unsigned num_mtt_segs; -}; - -struct mlx4_fw { - u64 clr_int_base; - u64 catas_offset; - u64 comm_base; - u64 clock_offset; - struct mlx4_icm *fw_icm; - struct mlx4_icm *aux_icm; - u32 catas_size; - u16 fw_pages; - u8 clr_int_bar; - u8 catas_bar; - u8 comm_bar; - u8 clock_bar; -}; - -struct mlx4_comm { - u32 slave_write; - u32 slave_read; -}; - -enum { - MLX4_MCAST_CONFIG = 0, - MLX4_MCAST_DISABLE = 1, - MLX4_MCAST_ENABLE = 2, -}; - -#define VLAN_FLTR_SIZE 128 - -struct mlx4_vlan_fltr { - __be32 entry[VLAN_FLTR_SIZE]; -}; - -struct mlx4_mcast_entry { - struct list_head list; - u64 addr; -}; - -struct mlx4_promisc_qp { - struct list_head list; - u32 qpn; -}; - -struct mlx4_steer_index { - struct list_head list; - unsigned int index; - struct list_head duplicates; -}; - -#define MLX4_EVENT_TYPES_NUM 64 - -struct mlx4_slave_state { - u8 comm_toggle; - u8 last_cmd; - u8 init_port_mask; - bool active; - bool old_vlan_api; - u8 function; - dma_addr_t vhcr_dma; - u16 mtu[MLX4_MAX_PORTS + 1]; - __be32 ib_cap_mask[MLX4_MAX_PORTS + 1]; - 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]; - /* event type to eq number lookup */ - struct mlx4_slave_event_eq_info event_eq[MLX4_EVENT_TYPES_NUM]; - u16 eq_pi; - u16 eq_ci; - spinlock_t lock; - /*initialized via the kzalloc*/ - u8 is_slave_going_down; - u32 cookie; - enum slave_port_state port_state[MLX4_MAX_PORTS + 1]; -}; - -#define MLX4_VGT 4095 -#define NO_INDX (-1) - - -struct mlx4_vport_state { - u64 mac; - u16 default_vlan; - u8 default_qos; - u32 tx_rate; - bool spoofchk; - u32 link_state; -}; - -struct mlx4_vf_admin_state { - struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_vport_oper_state { - struct mlx4_vport_state state; - int mac_idx; - int vlan_idx; -}; -struct mlx4_vf_oper_state { - struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1]; -}; - -struct slave_list { - struct mutex mutex; - struct list_head res_list[MLX4_NUM_OF_RESOURCE_TYPE]; -}; - -struct resource_allocator { - spinlock_t alloc_lock; - union { - int res_reserved; - int res_port_rsvd[MLX4_MAX_PORTS]; - }; - union { - int res_free; - int res_port_free[MLX4_MAX_PORTS]; - }; - int *quota; - int *allocated; - int *guaranteed; -}; - -struct mlx4_resource_tracker { - spinlock_t lock; - /* tree for each resources */ - struct rb_root res_tree[MLX4_NUM_OF_RESOURCE_TYPE]; - /* num_of_slave's lists, one per slave */ - struct slave_list *slave_list; - struct resource_allocator res_alloc[MLX4_NUM_OF_RESOURCE_TYPE]; -}; - -#define SLAVE_EVENT_EQ_SIZE 128 -struct mlx4_slave_event_eq { - u32 eqn; - u32 cons; - u32 prod; - spinlock_t event_lock; - struct mlx4_eqe event_eqe[SLAVE_EVENT_EQ_SIZE]; -}; - -struct mlx4_master_qp0_state { - int proxy_qp0_active; - int qp0_active; - int port_active; -}; - -struct mlx4_mfunc_master_ctx { - struct mlx4_slave_state *slave_state; - struct mlx4_vf_admin_state *vf_admin; - struct mlx4_vf_oper_state *vf_oper; - struct mlx4_master_qp0_state qp0_state[MLX4_MAX_PORTS + 1]; - int init_port_ref[MLX4_MAX_PORTS + 1]; - u16 max_mtu[MLX4_MAX_PORTS + 1]; - int disable_mcast_ref[MLX4_MAX_PORTS + 1]; - struct mlx4_resource_tracker res_tracker; - struct workqueue_struct *comm_wq; - struct work_struct comm_work; - struct work_struct arm_comm_work; - struct work_struct slave_event_work; - struct work_struct slave_flr_event_work; - spinlock_t slave_state_lock; - __be32 comm_arm_bit_vector[4]; - struct mlx4_eqe cmd_eqe; - struct mlx4_slave_event_eq slave_eq; - struct mutex gen_eqe_mutex[MLX4_MFUNC_MAX]; -}; - -struct mlx4_mfunc { - struct mlx4_comm __iomem *comm; - struct mlx4_vhcr_cmd *vhcr; - dma_addr_t vhcr_dma; - - struct mlx4_mfunc_master_ctx master; -}; - -#define MGM_QPN_MASK 0x00FFFFFF -#define MGM_BLCK_LB_BIT 30 - -struct mlx4_mgm { - __be32 next_gid_index; - __be32 members_count; - u32 reserved[2]; - u8 gid[16]; - __be32 qp[MLX4_MAX_QP_PER_MGM]; -}; - -struct mlx4_cmd { - struct pci_pool *pool; - void __iomem *hcr; - struct mutex hcr_mutex; - struct mutex slave_cmd_mutex; - struct semaphore poll_sem; - struct semaphore event_sem; - int max_cmds; - spinlock_t context_lock; - int free_head; - struct mlx4_cmd_context *context; - u16 token_mask; - u8 use_events; - u8 toggle; - u8 comm_toggle; -}; - -enum { - MLX4_VF_IMMED_VLAN_FLAG_VLAN = 1 << 0, - MLX4_VF_IMMED_VLAN_FLAG_QOS = 1 << 1, -}; -struct mlx4_vf_immed_vlan_work { - struct work_struct work; - struct mlx4_priv *priv; - int flags; - int slave; - int vlan_ix; - int orig_vlan_ix; - u8 port; - u8 qos; - u16 vlan_id; - u16 orig_vlan_id; -}; - - -struct mlx4_uar_table { - struct mlx4_bitmap bitmap; -}; - -struct mlx4_mr_table { - struct mlx4_bitmap mpt_bitmap; - struct mlx4_buddy mtt_buddy; - u64 mtt_base; - u64 mpt_base; - struct mlx4_icm_table mtt_table; - struct mlx4_icm_table dmpt_table; -}; - -struct mlx4_cq_table { - struct mlx4_bitmap bitmap; - spinlock_t lock; - rwlock_t cq_table_lock; - struct radix_tree_root tree; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_eq_table { - struct mlx4_bitmap bitmap; - char *irq_names; - void __iomem *clr_int; - void __iomem **uar_map; - u32 clr_mask; - struct mlx4_eq *eq; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; - int have_irq; - u8 inta_pin; -}; - -struct mlx4_srq_table { - struct mlx4_bitmap bitmap; - spinlock_t lock; - struct radix_tree_root tree; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_qp_table { - struct mlx4_bitmap bitmap; - u32 rdmarc_base; - int rdmarc_shift; - spinlock_t lock; - struct mlx4_icm_table qp_table; - struct mlx4_icm_table auxc_table; - struct mlx4_icm_table altc_table; - struct mlx4_icm_table rdmarc_table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_mcg_table { - struct mutex mutex; - struct mlx4_bitmap bitmap; - struct mlx4_icm_table table; -}; - -struct mlx4_catas_err { - u32 __iomem *map; - struct timer_list timer; - struct list_head list; -}; - -#define MLX4_MAX_MAC_NUM 128 -#define MLX4_MAC_TABLE_SIZE (MLX4_MAX_MAC_NUM << 3) - -struct mlx4_mac_table { - __be64 entries[MLX4_MAX_MAC_NUM]; - int refs[MLX4_MAX_MAC_NUM]; - struct mutex mutex; - int total; - int max; -}; - -#define MLX4_MAX_VLAN_NUM 128 -#define MLX4_VLAN_TABLE_SIZE (MLX4_MAX_VLAN_NUM << 2) - -struct mlx4_vlan_table { - __be32 entries[MLX4_MAX_VLAN_NUM]; - int refs[MLX4_MAX_VLAN_NUM]; - struct mutex mutex; - int total; - int max; -}; - -#define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_SHIFT 31 -#define SET_PORT_MC_PROMISC_SHIFT 30 - -enum { - MCAST_DIRECT_ONLY = 0, - MCAST_DIRECT = 1, - MCAST_DEFAULT = 2 -}; - - -struct mlx4_set_port_general_context { - u8 reserved[3]; - u8 flags; - u16 reserved2; - __be16 mtu; - u8 pptx; - u8 pfctx; - u16 reserved3; - u8 pprx; - u8 pfcrx; - u16 reserved4; -}; - -struct mlx4_set_port_rqp_calc_context { - __be32 base_qpn; - u8 rererved; - u8 n_mac; - u8 n_vlan; - u8 n_prio; - u8 reserved2[3]; - u8 mac_miss; - u8 intra_no_vlan; - u8 no_vlan; - u8 intra_vlan_miss; - u8 vlan_miss; - u8 reserved3[3]; - u8 no_vlan_prio; - __be32 promisc; - __be32 mcast; -}; - -struct mlx4_hca_info { - struct mlx4_dev *dev; - struct device_attribute firmware_attr; - struct device_attribute hca_attr; - struct device_attribute board_attr; -}; - -struct mlx4_port_info { - struct mlx4_dev *dev; - int port; - char dev_name[16]; - struct device_attribute port_attr; - enum mlx4_port_type tmp_type; - char dev_mtu_name[16]; - struct device_attribute port_mtu_attr; - struct mlx4_mac_table mac_table; - struct mlx4_vlan_table vlan_table; - int base_qpn; -}; - -struct mlx4_sense { - struct mlx4_dev *dev; - u8 do_sense_port[MLX4_MAX_PORTS + 1]; - u8 sense_allowed[MLX4_MAX_PORTS + 1]; - struct delayed_work sense_poll; -}; - -struct mlx4_msix_ctl { - u64 pool_bm; - struct mutex pool_lock; -}; - -struct mlx4_steer { - struct list_head promisc_qps[MLX4_NUM_STEERS]; - struct list_head steer_entries[MLX4_NUM_STEERS]; -}; - -enum { - MLX4_PCI_DEV_IS_VF = 1 << 0, - MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1, -}; - -struct mlx4_roce_gid_entry { - u8 raw[16]; -}; - -struct counter_index { - struct list_head list; - u32 index; -}; - -struct mlx4_counters { - struct mlx4_bitmap bitmap; - struct list_head global_port_list[MLX4_MAX_PORTS]; - struct list_head vf_list[MLX4_MAX_NUM_VF][MLX4_MAX_PORTS]; - struct mutex mutex; -}; - -enum { - MLX4_NO_RR = 0, - MLX4_USE_RR = 1, -}; - -struct mlx4_priv { - struct mlx4_dev dev; - - struct list_head dev_list; - struct list_head ctx_list; - spinlock_t ctx_lock; - - int pci_dev_data; - - struct list_head pgdir_list; - struct mutex pgdir_mutex; - - struct mlx4_fw fw; - struct mlx4_cmd cmd; - struct mlx4_mfunc mfunc; - - struct mlx4_bitmap pd_bitmap; - struct mlx4_bitmap xrcd_bitmap; - struct mlx4_uar_table uar_table; - struct mlx4_mr_table mr_table; - struct mlx4_cq_table cq_table; - struct mlx4_eq_table eq_table; - struct mlx4_srq_table srq_table; - struct mlx4_qp_table qp_table; - struct mlx4_mcg_table mcg_table; - struct mlx4_counters counters_table; - - struct mlx4_catas_err catas_err; - - void __iomem *clr_base; - - struct mlx4_uar driver_uar; - void __iomem *kar; - struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; - struct mlx4_hca_info hca_info; - struct mlx4_sense sense; - struct mutex port_mutex; - struct mlx4_msix_ctl msix_ctl; - struct mlx4_steer *steer; - struct list_head bf_list; - struct mutex bf_mutex; - struct io_mapping *bf_mapping; - void __iomem *clock_mapping; - int reserved_mtts; - int fs_hash_mode; - u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; - __be64 slave_node_guids[MLX4_MFUNC_MAX]; - struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][128]; - atomic_t opreq_count; - struct work_struct opreq_task; -}; - -static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) -{ - return container_of(dev, struct mlx4_priv, dev); -} - -#define MLX4_SENSE_RANGE (HZ * 3) - -extern struct workqueue_struct *mlx4_wq; - -u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr); -u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, - int align, u32 skip_mask); -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, - int use_rr); -u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); -int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, - u32 reserved_bot, u32 resetrved_top); -void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); - -int mlx4_reset(struct mlx4_dev *dev); - -int mlx4_alloc_eq_table(struct mlx4_dev *dev); -void mlx4_free_eq_table(struct mlx4_dev *dev); - -int mlx4_init_pd_table(struct mlx4_dev *dev); -int mlx4_init_xrcd_table(struct mlx4_dev *dev); -int mlx4_init_uar_table(struct mlx4_dev *dev); -int mlx4_init_mr_table(struct mlx4_dev *dev); -int mlx4_init_eq_table(struct mlx4_dev *dev); -int mlx4_init_cq_table(struct mlx4_dev *dev); -int mlx4_init_qp_table(struct mlx4_dev *dev); -int mlx4_init_srq_table(struct mlx4_dev *dev); -int mlx4_init_mcg_table(struct mlx4_dev *dev); - -void mlx4_cleanup_pd_table(struct mlx4_dev *dev); -void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev); -void mlx4_cleanup_uar_table(struct mlx4_dev *dev); -void mlx4_cleanup_mr_table(struct mlx4_dev *dev); -void mlx4_cleanup_eq_table(struct mlx4_dev *dev); -void mlx4_cleanup_cq_table(struct mlx4_dev *dev); -void mlx4_cleanup_qp_table(struct mlx4_dev *dev); -void mlx4_cleanup_srq_table(struct mlx4_dev *dev); -void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); -int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn); -void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn); -int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn); -void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn); -int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn); -void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn); -int __mlx4_mpt_reserve(struct mlx4_dev *dev); -void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index); -int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index); -void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index); -u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order); -void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order); - -int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SYNC_TPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags); -void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); -int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac); -void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac); -int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list); -int __mlx4_counter_alloc(struct mlx4_dev *dev, int slave, int port, u32 *idx); -void __mlx4_counter_free(struct mlx4_dev *dev, int slave, int port, u32 idx); - -int __mlx4_slave_counters_free(struct mlx4_dev *dev, int slave); -int __mlx4_clear_if_stat(struct mlx4_dev *dev, - u8 counter_index); -u8 mlx4_get_default_counter_index(struct mlx4_dev *dev, int slave, int port); - -int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn); -void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); - -void mlx4_start_catas_poll(struct mlx4_dev *dev); -void mlx4_stop_catas_poll(struct mlx4_dev *dev); -void mlx4_catas_init(void); -int mlx4_restart_one(struct pci_dev *pdev); -int mlx4_register_device(struct mlx4_dev *dev); -void mlx4_unregister_device(struct mlx4_dev *dev); -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, - unsigned long param); - -struct mlx4_dev_cap; -struct mlx4_init_hca_param; - -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_master_comm_channel(struct work_struct *work); -void mlx4_master_arm_comm_channel(struct work_struct *work); -void mlx4_gen_slave_eqe(struct work_struct *work); -void mlx4_master_handle_slave_flr(struct work_struct *work); - -int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -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_cmd_info *cmd); -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_cmd_info *cmd); -int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_2ERR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTS2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -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); -int mlx4_multi_func_init(struct mlx4_dev *dev); -void mlx4_multi_func_cleanup(struct mlx4_dev *dev); -void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); -int mlx4_cmd_use_events(struct mlx4_dev *dev); -void mlx4_cmd_use_polling(struct mlx4_dev *dev); - -int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout); - -void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); -void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type); - -void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); - -void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); - -void mlx4_handle_catas_err(struct mlx4_dev *dev); - -int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type); -void mlx4_do_sense_ports(struct mlx4_dev *dev, - enum mlx4_port_type *stype, - enum mlx4_port_type *defaults); -void mlx4_start_sense(struct mlx4_dev *dev); -void mlx4_stop_sense(struct mlx4_dev *dev); -void mlx4_sense_init(struct mlx4_dev *dev); -int mlx4_check_port_params(struct mlx4_dev *dev, - enum mlx4_port_type *port_type); -int mlx4_change_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *port_types); - -void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); -void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); -void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan); -int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); - -int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz); -/* resource tracker functions*/ -int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, - enum mlx4_resource resource_type, - u64 resource_id, int *slave); -void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave_id); -int mlx4_init_resource_tracker(struct mlx4_dev *dev); - -void mlx4_free_resource_tracker(struct mlx4_dev *dev, - enum mlx4_res_tracker_free_type type); - -int mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); - -int mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port, - int *gid_tbl_len, int *pkey_tbl_len); - -int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type steer); -int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type steer); -int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 port, - int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id); -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); -int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_common_set_vlan_fltr(struct mlx4_dev *dev, int function, - int port, void *buf); -int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_PKEY_TABLE_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MOD_STAT_CFG_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -int mlx4_get_mgm_entry_size(struct mlx4_dev *dev); -int mlx4_get_qp_per_mgm(struct mlx4_dev *dev); - -static inline void set_param_l(u64 *arg, u32 val) -{ - *arg = (*arg & 0xffffffff00000000ULL) | (u64) val; -} - -static inline void set_param_h(u64 *arg, u32 val) -{ - *arg = (*arg & 0xffffffff) | ((u64) val << 32); -} - -static inline u32 get_param_l(u64 *arg) -{ - return (u32) (*arg & 0xffffffff); -} - -static inline u32 get_param_h(u64 *arg) -{ - return (u32)(*arg >> 32); -} - -static inline spinlock_t *mlx4_tlock(struct mlx4_dev *dev) -{ - return &mlx4_priv(dev)->mfunc.master.res_tracker.lock; -} - -#define NOT_MASKED_PD_BITS 17 - -void sys_tune_init(void); -void sys_tune_fini(void); - -void mlx4_init_quotas(struct mlx4_dev *dev); - -int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave); -int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave); -void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work); - -#endif /* MLX4_H */ diff --git a/sys/ofed/drivers/net/mlx4/mlx4_en.h b/sys/ofed/drivers/net/mlx4/mlx4_en.h deleted file mode 100644 index 17afa9e44022..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4_en.h +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef _MLX4_EN_H_ -#define _MLX4_EN_H_ - -#include <linux/bitops.h> -#include <linux/compiler.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/kobject.h> -#include <linux/netdevice.h> -#include <linux/if_vlan.h> -#include <linux/if_ether.h> -#ifdef CONFIG_MLX4_EN_DCB -#include <linux/dcbnl.h> -#endif - -#include <linux/mlx4/device.h> -#include <linux/mlx4/qp.h> -#include <linux/mlx4/cq.h> -#include <linux/mlx4/srq.h> -#include <linux/mlx4/doorbell.h> -#include <linux/mlx4/cmd.h> - -#include <netinet/tcp_lro.h> - -#include "en_port.h" -#include "mlx4_stats.h" - -#define DRV_NAME "mlx4_en" - -#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) - -/* - * Device constants - */ - - -#define MLX4_EN_PAGE_SHIFT 12 -#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) -#define MLX4_NET_IP_ALIGN 2 /* bytes */ -#define DEF_RX_RINGS 16 -#define MAX_RX_RINGS 128 -#define MIN_RX_RINGS 4 -#define TXBB_SIZE 64 -#define HEADROOM (2048 / TXBB_SIZE + 1) -#define STAMP_STRIDE 64 -#define STAMP_DWORDS (STAMP_STRIDE / 4) -#define STAMP_SHIFT 31 -#define STAMP_VAL 0x7fffffff -#define STATS_DELAY (HZ / 4) -#define SERVICE_TASK_DELAY (HZ / 4) -#define MAX_NUM_OF_FS_RULES 256 - -#define MLX4_EN_FILTER_HASH_SHIFT 4 -#define MLX4_EN_FILTER_EXPIRY_QUOTA 60 - -#ifdef CONFIG_NET_RX_BUSY_POLL -#define LL_EXTENDED_STATS -#endif - -/* vlan valid range */ -#define VLAN_MIN_VALUE 1 -#define VLAN_MAX_VALUE 4094 - -/* - * OS related constants and tunables - */ - -#define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) - -#define MLX4_EN_ALLOC_SIZE PAGE_ALIGN(PAGE_SIZE) -#define MLX4_EN_ALLOC_ORDER get_order(MLX4_EN_ALLOC_SIZE) - -enum mlx4_en_alloc_type { - MLX4_EN_ALLOC_NEW = 0, - MLX4_EN_ALLOC_REPLACEMENT = 1, -}; - -/* Maximum ring sizes */ -#define MLX4_EN_DEF_TX_QUEUE_SIZE 4096 - -/* Minimum packet number till arming the CQ */ -#define MLX4_EN_MIN_RX_ARM 2048 -#define MLX4_EN_MIN_TX_ARM 2048 - -/* Maximum ring sizes */ -#define MLX4_EN_MAX_TX_SIZE 8192 -#define MLX4_EN_MAX_RX_SIZE 8192 - -/* Minimum ring sizes */ -#define MLX4_EN_MIN_RX_SIZE (4096 / TXBB_SIZE) -#define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) - -#define MLX4_EN_SMALL_PKT_SIZE 64 - -#define MLX4_EN_MAX_TX_RING_P_UP 32 -#define MLX4_EN_NUM_UP 1 - -#define MAX_TX_RINGS (MLX4_EN_MAX_TX_RING_P_UP * \ - MLX4_EN_NUM_UP) - -#define MLX4_EN_DEF_TX_RING_SIZE 1024 -#define MLX4_EN_DEF_RX_RING_SIZE 1024 - -/* Target number of bytes to coalesce with interrupt moderation */ -#define MLX4_EN_RX_COAL_TARGET 0x20000 -#define MLX4_EN_RX_COAL_TIME 0x10 - -#define MLX4_EN_TX_COAL_PKTS 64 -#define MLX4_EN_TX_COAL_TIME 64 - -#define MLX4_EN_RX_RATE_LOW 400000 -#define MLX4_EN_RX_COAL_TIME_LOW 0 -#define MLX4_EN_RX_RATE_HIGH 450000 -#define MLX4_EN_RX_COAL_TIME_HIGH 128 -#define MLX4_EN_RX_SIZE_THRESH 1024 -#define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) -#define MLX4_EN_SAMPLE_INTERVAL 0 -#define MLX4_EN_AVG_PKT_SMALL 256 - -#define MLX4_EN_AUTO_CONF 0xffff - -#define MLX4_EN_DEF_RX_PAUSE 1 -#define MLX4_EN_DEF_TX_PAUSE 1 - -/* Interval between successive polls in the Tx routine when polling is used - instead of interrupts (in per-core Tx rings) - should be power of 2 */ -#define MLX4_EN_TX_POLL_MODER 16 -#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4) - -#define MLX4_EN_64_ALIGN (64 - NET_SKB_PAD) -#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) -#define HEADER_COPY_SIZE (128) -#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETHER_HDR_LEN) - -#define MLX4_EN_MIN_MTU 46 -#define ETH_BCAST 0xffffffffffffULL - -#define MLX4_EN_LOOPBACK_RETRIES 5 -#define MLX4_EN_LOOPBACK_TIMEOUT 100 - -#ifdef MLX4_EN_PERF_STAT -/* Number of samples to 'average' */ -#define AVG_SIZE 128 -#define AVG_FACTOR 1024 - -#define INC_PERF_COUNTER(cnt) (++(cnt)) -#define ADD_PERF_COUNTER(cnt, add) ((cnt) += (add)) -#define AVG_PERF_COUNTER(cnt, sample) \ - ((cnt) = ((cnt) * (AVG_SIZE - 1) + (sample) * AVG_FACTOR) / AVG_SIZE) -#define GET_PERF_COUNTER(cnt) (cnt) -#define GET_AVG_PERF_COUNTER(cnt) ((cnt) / AVG_FACTOR) - -#else - -#define INC_PERF_COUNTER(cnt) do {} while (0) -#define ADD_PERF_COUNTER(cnt, add) do {} while (0) -#define AVG_PERF_COUNTER(cnt, sample) do {} while (0) -#define GET_PERF_COUNTER(cnt) (0) -#define GET_AVG_PERF_COUNTER(cnt) (0) -#endif /* MLX4_EN_PERF_STAT */ - -/* - * Configurables - */ - -enum cq_type { - RX = 0, - TX = 1, -}; - - -/* - * Useful macros - */ -#define ROUNDUP_LOG2(x) ilog2(roundup_pow_of_two(x)) -#define XNOR(x, y) (!(x) == !(y)) -#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0) - -struct mlx4_en_tx_info { - bus_dmamap_t dma_map; - struct mbuf *mb; - u32 nr_txbb; - u32 nr_bytes; -}; - - -#define MLX4_EN_BIT_DESC_OWN 0x80000000 -#define CTRL_SIZE sizeof(struct mlx4_wqe_ctrl_seg) -#define MLX4_EN_MEMTYPE_PAD 0x100 -#define DS_SIZE sizeof(struct mlx4_wqe_data_seg) - - -struct mlx4_en_tx_desc { - struct mlx4_wqe_ctrl_seg ctrl; - union { - struct mlx4_wqe_data_seg data; /* at least one data segment */ - struct mlx4_wqe_lso_seg lso; - struct mlx4_wqe_inline_seg inl; - }; -}; - -#define MLX4_EN_USE_SRQ 0x01000000 - -#define MLX4_EN_RX_BUDGET 64 - -#define MLX4_EN_TX_MAX_DESC_SIZE 512 /* bytes */ -#define MLX4_EN_TX_MAX_MBUF_SIZE 65536 /* bytes */ -#define MLX4_EN_TX_MAX_PAYLOAD_SIZE 65536 /* bytes */ -#define MLX4_EN_TX_MAX_MBUF_FRAGS \ - ((MLX4_EN_TX_MAX_DESC_SIZE - 128) / DS_SIZE_ALIGNMENT) /* units */ -#define MLX4_EN_TX_WQE_MAX_WQEBBS \ - (MLX4_EN_TX_MAX_DESC_SIZE / TXBB_SIZE) /* units */ - -#define MLX4_EN_CX3_LOW_ID 0x1000 -#define MLX4_EN_CX3_HIGH_ID 0x1005 - -struct mlx4_en_tx_ring { - spinlock_t tx_lock; - bus_dma_tag_t dma_tag; - struct mlx4_hwq_resources wqres; - u32 size ; /* number of TXBBs */ - u32 size_mask; - u16 stride; - u16 cqn; /* index of port CQ associated with this ring */ - u32 prod; - u32 cons; - u32 buf_size; - u32 doorbell_qpn; - u8 *buf; - u16 poll_cnt; - int blocked; - struct mlx4_en_tx_info *tx_info; - u8 queue_index; - cpuset_t affinity_mask; - struct buf_ring *br; - u32 last_nr_txbb; - struct mlx4_qp qp; - struct mlx4_qp_context context; - int qpn; - enum mlx4_qp_state qp_state; - struct mlx4_srq dummy; - unsigned long bytes; - unsigned long packets; - unsigned long tx_csum; - unsigned long queue_stopped; - unsigned long oversized_packets; - unsigned long wake_queue; - struct mlx4_bf bf; - bool bf_enabled; - int hwtstamp_tx_type; - spinlock_t comp_lock; - int inline_thold; - u64 watchdog_time; -}; - -struct mlx4_en_rx_desc { - /* actual number of entries depends on rx ring stride */ - struct mlx4_wqe_data_seg data[0]; -}; - -struct mlx4_en_rx_mbuf { - bus_dmamap_t dma_map; - struct mbuf *mbuf; -}; - -struct mlx4_en_rx_spare { - bus_dmamap_t dma_map; - struct mbuf *mbuf; - u64 paddr_be; -}; - -struct mlx4_en_rx_ring { - struct mlx4_hwq_resources wqres; - bus_dma_tag_t dma_tag; - struct mlx4_en_rx_spare spare; - u32 size ; /* number of Rx descs*/ - u32 actual_size; - u32 size_mask; - u16 stride; - u16 log_stride; - u16 cqn; /* index of port CQ associated with this ring */ - u32 prod; - u32 cons; - u32 buf_size; - u8 fcs_del; - u32 rx_mb_size; - int qpn; - u8 *buf; - struct mlx4_en_rx_mbuf *mbuf; - unsigned long errors; - unsigned long bytes; - unsigned long packets; -#ifdef LL_EXTENDED_STATS - unsigned long yields; - unsigned long misses; - unsigned long cleaned; -#endif - unsigned long csum_ok; - unsigned long csum_none; - int hwtstamp_rx_filter; - int numa_node; - struct lro_ctrl lro; -}; - -static inline int mlx4_en_can_lro(__be16 status) -{ - const __be16 status_all = cpu_to_be16( - MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPV4F | - MLX4_CQE_STATUS_IPV6 | - MLX4_CQE_STATUS_IPV4OPT | - MLX4_CQE_STATUS_TCP | - MLX4_CQE_STATUS_UDP | - MLX4_CQE_STATUS_IPOK); - const __be16 status_ipv4_ipok_tcp = cpu_to_be16( - MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPOK | - MLX4_CQE_STATUS_TCP); - const __be16 status_ipv6_ipok_tcp = cpu_to_be16( - MLX4_CQE_STATUS_IPV6 | - MLX4_CQE_STATUS_IPOK | - MLX4_CQE_STATUS_TCP); - - status &= status_all; - return (status == status_ipv4_ipok_tcp || - status == status_ipv6_ipok_tcp); -} - -struct mlx4_en_cq { - struct mlx4_cq mcq; - struct mlx4_hwq_resources wqres; - int ring; - spinlock_t lock; - struct net_device *dev; - /* Per-core Tx cq processing support */ - struct timer_list timer; - int size; - int buf_size; - unsigned vector; - enum cq_type is_tx; - u16 moder_time; - u16 moder_cnt; - struct mlx4_cqe *buf; - struct task cq_task; - struct taskqueue *tq; -#define MLX4_EN_OPCODE_ERROR 0x1e - u32 tot_rx; - u32 tot_tx; - u32 curr_poll_rx_cpu_id; - -#ifdef CONFIG_NET_RX_BUSY_POLL - unsigned int state; -#define MLX4_EN_CQ_STATEIDLE 0 -#define MLX4_EN_CQ_STATENAPI 1 /* NAPI owns this CQ */ -#define MLX4_EN_CQ_STATEPOLL 2 /* poll owns this CQ */ -#define MLX4_CQ_LOCKED (MLX4_EN_CQ_STATENAPI | MLX4_EN_CQ_STATEPOLL) -#define MLX4_EN_CQ_STATENAPI_YIELD 4 /* NAPI yielded this CQ */ -#define MLX4_EN_CQ_STATEPOLL_YIELD 8 /* poll yielded this CQ */ -#define CQ_YIELD (MLX4_EN_CQ_STATENAPI_YIELD | MLX4_EN_CQ_STATEPOLL_YIELD) -#define CQ_USER_PEND (MLX4_EN_CQ_STATEPOLL | MLX4_EN_CQ_STATEPOLL_YIELD) - spinlock_t poll_lock; /* protects from LLS/napi conflicts */ -#endif /* CONFIG_NET_RX_BUSY_POLL */ -}; - -struct mlx4_en_port_profile { - u32 flags; - u32 tx_ring_num; - u32 rx_ring_num; - u32 tx_ring_size; - u32 rx_ring_size; - u8 rx_pause; - u8 rx_ppp; - u8 tx_pause; - u8 tx_ppp; - int rss_rings; -}; - -struct mlx4_en_profile { - int rss_xor; - int udp_rss; - u8 rss_mask; - u32 active_ports; - u32 small_pkt_int; - u8 no_reset; - u8 num_tx_rings_p_up; - struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_en_dev { - struct mlx4_dev *dev; - struct pci_dev *pdev; - struct mutex state_lock; - struct net_device *pndev[MLX4_MAX_PORTS + 1]; - u32 port_cnt; - bool device_up; - struct mlx4_en_profile profile; - u32 LSO_support; - struct workqueue_struct *workqueue; - struct device *dma_device; - void __iomem *uar_map; - struct mlx4_uar priv_uar; - struct mlx4_mr mr; - u32 priv_pdn; - spinlock_t uar_lock; - u8 mac_removed[MLX4_MAX_PORTS + 1]; - unsigned long last_overflow_check; - unsigned long overflow_period; -}; - - -struct mlx4_en_rss_map { - int base_qpn; - struct mlx4_qp qps[MAX_RX_RINGS]; - enum mlx4_qp_state state[MAX_RX_RINGS]; - struct mlx4_qp indir_qp; - enum mlx4_qp_state indir_state; -}; - -struct mlx4_en_port_state { - int link_state; - int link_speed; - int transciver; - int autoneg; -}; - -enum mlx4_en_mclist_act { - MCLIST_NONE, - MCLIST_REM, - MCLIST_ADD, -}; - -struct mlx4_en_mc_list { - struct list_head list; - enum mlx4_en_mclist_act action; - u8 addr[ETH_ALEN]; - u64 reg_id; -}; - -#ifdef CONFIG_MLX4_EN_DCB -/* Minimal TC BW - setting to 0 will block traffic */ -#define MLX4_EN_BW_MIN 1 -#define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ - -#define MLX4_EN_TC_ETS 7 - -#endif - - -enum { - MLX4_EN_FLAG_PROMISC = (1 << 0), - MLX4_EN_FLAG_MC_PROMISC = (1 << 1), - /* whether we need to enable hardware loopback by putting dmac - * in Tx WQE - */ - MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2), - /* whether we need to drop packets that hardware loopback-ed */ - MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3), - MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4), -#ifdef CONFIG_MLX4_EN_DCB - MLX4_EN_FLAG_DCB_ENABLED = (1 << 5) -#endif -}; - -#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) -#define MLX4_EN_MAC_HASH_IDX 5 - -struct en_port { - struct kobject kobj; - struct mlx4_dev *dev; - u8 port_num; - u8 vport_num; -}; - -struct mlx4_en_priv { - struct mlx4_en_dev *mdev; - struct mlx4_en_port_profile *prof; - struct net_device *dev; - unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct mlx4_en_port_state port_state; - spinlock_t stats_lock; - /* To allow rules removal while port is going down */ - struct list_head ethtool_list; - - unsigned long last_moder_packets[MAX_RX_RINGS]; - unsigned long last_moder_tx_packets; - unsigned long last_moder_bytes[MAX_RX_RINGS]; - unsigned long last_moder_jiffies; - int last_moder_time[MAX_RX_RINGS]; - u16 rx_usecs; - u16 rx_frames; - u16 tx_usecs; - u16 tx_frames; - u32 pkt_rate_low; - u32 rx_usecs_low; - u32 pkt_rate_high; - u32 rx_usecs_high; - u32 sample_interval; - u32 adaptive_rx_coal; - u32 msg_enable; - u32 loopback_ok; - u32 validate_loopback; - - struct mlx4_hwq_resources res; - int link_state; - int last_link_state; - bool port_up; - int port; - int registered; - int allocated; - int stride; - unsigned char current_mac[ETH_ALEN + 2]; - u64 mac; - int mac_index; - unsigned max_mtu; - int base_qpn; - int cqe_factor; - - struct mlx4_en_rss_map rss_map; - u32 flags; - u8 num_tx_rings_p_up; - u32 tx_ring_num; - u32 rx_ring_num; - u32 rx_mb_size; - - struct mlx4_en_tx_ring **tx_ring; - struct mlx4_en_rx_ring *rx_ring[MAX_RX_RINGS]; - struct mlx4_en_cq **tx_cq; - struct mlx4_en_cq *rx_cq[MAX_RX_RINGS]; - struct mlx4_qp drop_qp; - struct work_struct rx_mode_task; - struct work_struct watchdog_task; - struct work_struct linkstate_task; - struct delayed_work stats_task; - struct delayed_work service_task; - struct mlx4_en_perf_stats pstats; - struct mlx4_en_pkt_stats pkstats; - struct mlx4_en_pkt_stats pkstats_last; - struct mlx4_en_flow_stats flowstats[MLX4_NUM_PRIORITIES]; - struct mlx4_en_port_stats port_stats; - struct mlx4_en_vport_stats vport_stats; - struct mlx4_en_vf_stats vf_stats; - DECLARE_BITMAP(stats_bitmap, NUM_ALL_STATS); - struct list_head mc_list; - struct list_head curr_list; - u64 broadcast_id; - struct mlx4_en_stat_out_mbox hw_stats; - int vids[128]; - bool wol; - struct device *ddev; - struct dentry *dev_root; - u32 counter_index; - eventhandler_tag vlan_attach; - eventhandler_tag vlan_detach; - struct callout watchdog_timer; - struct ifmedia media; - volatile int blocked; - struct sysctl_oid *sysctl; - struct sysctl_ctx_list conf_ctx; - struct sysctl_ctx_list stat_ctx; -#define MLX4_EN_MAC_HASH_IDX 5 - struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; - -#ifdef CONFIG_MLX4_EN_DCB - struct ieee_ets ets; - u16 maxrate[IEEE_8021QAZ_MAX_TCS]; - u8 dcbx_cap; -#endif -#ifdef CONFIG_RFS_ACCEL - spinlock_t filters_lock; - int last_filter_id; - struct list_head filters; - struct hlist_head filter_hash[1 << MLX4_EN_FILTER_HASH_SHIFT]; -#endif - struct en_port *vf_ports[MLX4_MAX_NUM_VF]; - unsigned long last_ifq_jiffies; - u64 if_counters_rx_errors; - u64 if_counters_rx_no_buffer; -}; - -enum mlx4_en_wol { - MLX4_EN_WOL_MAGIC = (1ULL << 61), - MLX4_EN_WOL_ENABLED = (1ULL << 62), -}; - -struct mlx4_mac_entry { - struct hlist_node hlist; - unsigned char mac[ETH_ALEN + 2]; - u64 reg_id; -}; - -#ifdef CONFIG_NET_RX_BUSY_POLL -static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) -{ - spin_lock_init(&cq->poll_lock); - cq->state = MLX4_EN_CQ_STATEIDLE; -} - -/* called from the device poll rutine to get ownership of a cq */ -static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq) -{ - int rc = true; - spin_lock(&cq->poll_lock); - if (cq->state & MLX4_CQ_LOCKED) { - WARN_ON(cq->state & MLX4_EN_CQ_STATENAPI); - cq->state |= MLX4_EN_CQ_STATENAPI_YIELD; - rc = false; - } else - /* we don't care if someone yielded */ - cq->state = MLX4_EN_CQ_STATENAPI; - spin_unlock(&cq->poll_lock); - return rc; -} - -/* returns true is someone tried to get the cq while napi had it */ -static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq) -{ - int rc = false; - spin_lock(&cq->poll_lock); - WARN_ON(cq->state & (MLX4_EN_CQ_STATEPOLL | - MLX4_EN_CQ_STATENAPI_YIELD)); - - if (cq->state & MLX4_EN_CQ_STATEPOLL_YIELD) - rc = true; - cq->state = MLX4_EN_CQ_STATEIDLE; - spin_unlock(&cq->poll_lock); - return rc; -} - -/* called from mlx4_en_low_latency_poll() */ -static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq) -{ - int rc = true; - spin_lock_bh(&cq->poll_lock); - if ((cq->state & MLX4_CQ_LOCKED)) { - struct net_device *dev = cq->dev; - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; - - cq->state |= MLX4_EN_CQ_STATEPOLL_YIELD; - rc = false; -#ifdef LL_EXTENDED_STATS - rx_ring->yields++; -#endif - } else - /* preserve yield marks */ - cq->state |= MLX4_EN_CQ_STATEPOLL; - spin_unlock_bh(&cq->poll_lock); - return rc; -} - -/* returns true if someone tried to get the cq while it was locked */ -static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) -{ - int rc = false; - spin_lock_bh(&cq->poll_lock); - WARN_ON(cq->state & (MLX4_EN_CQ_STATENAPI)); - - if (cq->state & MLX4_EN_CQ_STATEPOLL_YIELD) - rc = true; - cq->state = MLX4_EN_CQ_STATEIDLE; - spin_unlock_bh(&cq->poll_lock); - return rc; -} - -/* true if a socket is polling, even if it did not get the lock */ -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) -{ - WARN_ON(!(cq->state & MLX4_CQ_LOCKED)); - return cq->state & CQ_USER_PEND; -} -#else -static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) -{ -} - -static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq) -{ - return true; -} - -static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) -{ - return false; -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) - -void mlx4_en_destroy_netdev(struct net_device *dev); -int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, - struct mlx4_en_port_profile *prof); - -int mlx4_en_start_port(struct net_device *dev); -void mlx4_en_stop_port(struct net_device *dev); - -void mlx4_en_free_resources(struct mlx4_en_priv *priv); -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); - -int mlx4_en_pre_config(struct mlx4_en_priv *priv); -int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq, - int entries, int ring, enum cq_type mode, int node); -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq); -int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, - int cq_idx); -void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); - -void mlx4_en_tx_irq(struct mlx4_cq *mcq); -u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb); - -int mlx4_en_transmit(struct ifnet *dev, struct mbuf *m); -int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring, - u32 size, u16 stride, int node, int queue_idx); -void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring); -int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, - int cq, int user_prio); -void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring); -void mlx4_en_qflush(struct ifnet *dev); - -int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, int node); -void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, u16 stride); -void mlx4_en_tx_que(void *context, int pending); -void mlx4_en_rx_que(void *context, int pending); -int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv); -void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring); -int mlx4_en_process_rx_cq(struct net_device *dev, - struct mlx4_en_cq *cq, - int budget); -void mlx4_en_poll_tx_cq(unsigned long data); -void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int user_prio, - struct mlx4_qp_context *context); -void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); -int mlx4_en_map_buffer(struct mlx4_buf *buf); -void mlx4_en_unmap_buffer(struct mlx4_buf *buf); -void mlx4_en_calc_rx_buf(struct net_device *dev); - -int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); -void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); -int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv); -void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv); -int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -void mlx4_en_rx_irq(struct mlx4_cq *mcq); - -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); -int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv); - -int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); -int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); -int mlx4_en_get_vport_stats(struct mlx4_en_dev *mdev, u8 port); -void mlx4_en_create_debug_files(struct mlx4_en_priv *priv); -void mlx4_en_delete_debug_files(struct mlx4_en_priv *priv); -int mlx4_en_register_debugfs(void); -void mlx4_en_unregister_debugfs(void); - -#ifdef CONFIG_MLX4_EN_DCB -extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops; -extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops; -#endif - -int mlx4_en_setup_tc(struct net_device *dev, u8 up); - -#ifdef CONFIG_RFS_ACCEL -void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *rx_ring); -#endif - -#define MLX4_EN_NUM_SELF_TEST 5 -void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); -void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev); - -/* - * Functions for time stamping - */ -#define SKBTX_HW_TSTAMP (1 << 0) -#define SKBTX_IN_PROGRESS (1 << 2) - -u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe); - -/* Functions for caching and restoring statistics */ -int mlx4_en_get_sset_count(struct net_device *dev, int sset); -void mlx4_en_restore_ethtool_stats(struct mlx4_en_priv *priv, - u64 *data); - -/* - * Globals - */ -extern const struct ethtool_ops mlx4_en_ethtool_ops; - -/* - * Defines for link speed - needed by selftest - */ -#define MLX4_EN_LINK_SPEED_1G 1000 -#define MLX4_EN_LINK_SPEED_10G 10000 -#define MLX4_EN_LINK_SPEED_40G 40000 - -enum { - NETIF_MSG_DRV = 0x0001, - NETIF_MSG_PROBE = 0x0002, - NETIF_MSG_LINK = 0x0004, - NETIF_MSG_TIMER = 0x0008, - NETIF_MSG_IFDOWN = 0x0010, - NETIF_MSG_IFUP = 0x0020, - NETIF_MSG_RX_ERR = 0x0040, - NETIF_MSG_TX_ERR = 0x0080, - NETIF_MSG_TX_QUEUED = 0x0100, - NETIF_MSG_INTR = 0x0200, - NETIF_MSG_TX_DONE = 0x0400, - NETIF_MSG_RX_STATUS = 0x0800, - NETIF_MSG_PKTDATA = 0x1000, - NETIF_MSG_HW = 0x2000, - NETIF_MSG_WOL = 0x4000, -}; - - -/* - * printk / logging functions - */ - -#define en_print(level, priv, format, arg...) \ - { \ - if ((priv)->registered) \ - printk(level "%s: %s: " format, DRV_NAME, \ - (priv->dev)->if_xname, ## arg); \ - else \ - printk(level "%s: %s: Port %d: " format, \ - DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ - (priv)->port, ## arg); \ - } - - -#define en_dbg(mlevel, priv, format, arg...) \ -do { \ - if (NETIF_MSG_##mlevel & priv->msg_enable) \ - en_print(KERN_DEBUG, priv, format, ##arg); \ -} while (0) -#define en_warn(priv, format, arg...) \ - en_print(KERN_WARNING, priv, format, ##arg) -#define en_err(priv, format, arg...) \ - en_print(KERN_ERR, priv, format, ##arg) -#define en_info(priv, format, arg...) \ - en_print(KERN_INFO, priv, format, ## arg) - -#define mlx4_err(mdev, format, arg...) \ - pr_err("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) -#define mlx4_info(mdev, format, arg...) \ - pr_info("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) -#define mlx4_warn(mdev, format, arg...) \ - pr_warning("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) - -#endif diff --git a/sys/ofed/drivers/net/mlx4/mlx4_stats.h b/sys/ofed/drivers/net/mlx4/mlx4_stats.h deleted file mode 100644 index ef0b1c0a679b..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4_stats.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2014 Mellanox Technologies Ltd. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _MLX4_STATS_ -#define _MLX4_STATS_ - - -#ifdef MLX4_EN_PERF_STAT -#define NUM_PERF_STATS NUM_PERF_COUNTERS -#else -#define NUM_PERF_STATS 0 -#endif - -#define NUM_PRIORITIES 9 -#define NUM_PRIORITY_STATS 2 - -struct mlx4_en_pkt_stats { - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_broadcast_packets; - unsigned long rx_errors; - unsigned long rx_dropped; - unsigned long rx_length_errors; - unsigned long rx_over_errors; - unsigned long rx_crc_errors; - unsigned long rx_jabbers; - unsigned long rx_in_range_length_error; - unsigned long rx_out_range_length_error; - unsigned long rx_lt_64_bytes_packets; - unsigned long rx_127_bytes_packets; - unsigned long rx_255_bytes_packets; - unsigned long rx_511_bytes_packets; - unsigned long rx_1023_bytes_packets; - unsigned long rx_1518_bytes_packets; - unsigned long rx_1522_bytes_packets; - unsigned long rx_1548_bytes_packets; - unsigned long rx_gt_1548_bytes_packets; - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; - unsigned long tx_dropped; - unsigned long tx_lt_64_bytes_packets; - unsigned long tx_127_bytes_packets; - unsigned long tx_255_bytes_packets; - unsigned long tx_511_bytes_packets; - unsigned long tx_1023_bytes_packets; - unsigned long tx_1518_bytes_packets; - unsigned long tx_1522_bytes_packets; - unsigned long tx_1548_bytes_packets; - unsigned long tx_gt_1548_bytes_packets; - unsigned long rx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; - unsigned long tx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; -#define NUM_PKT_STATS 72 -}; - -struct mlx4_en_vf_stats { - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_broadcast_packets; - unsigned long rx_errors; - unsigned long rx_dropped; - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; -#define NUM_VF_STATS 11 -}; - -struct mlx4_en_vport_stats { - unsigned long rx_unicast_packets; - unsigned long rx_unicast_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_multicast_bytes; - unsigned long rx_broadcast_packets; - unsigned long rx_broadcast_bytes; - unsigned long rx_dropped; - unsigned long rx_errors; - unsigned long tx_unicast_packets; - unsigned long tx_unicast_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_multicast_bytes; - unsigned long tx_broadcast_packets; - unsigned long tx_broadcast_bytes; - unsigned long tx_errors; -#define NUM_VPORT_STATS 15 -}; - -struct mlx4_en_port_stats { - unsigned long tso_packets; - unsigned long queue_stopped; - unsigned long wake_queue; - unsigned long tx_timeout; - unsigned long oversized_packets; - unsigned long rx_alloc_failed; - unsigned long rx_chksum_good; - unsigned long rx_chksum_none; - unsigned long tx_chksum_offload; -#define NUM_PORT_STATS 8 -}; - -struct mlx4_en_perf_stats { - u32 tx_poll; - u64 tx_pktsz_avg; - u32 inflight_avg; - u16 tx_coal_avg; - u16 rx_coal_avg; - u32 napi_quota; -#define NUM_PERF_COUNTERS 6 -}; - -struct mlx4_en_flow_stats { - u64 rx_pause; - u64 rx_pause_duration; - u64 rx_pause_transition; - u64 tx_pause; - u64 tx_pause_duration; - u64 tx_pause_transition; -}; -#define MLX4_NUM_PRIORITIES 8 -#define NUM_FLOW_PRIORITY_STATS 6 -#define NUM_FLOW_STATS (NUM_FLOW_PRIORITY_STATS*MLX4_NUM_PRIORITIES) - - -struct mlx4_en_stat_out_flow_control_mbox { - /* Total number of PAUSE frames received from the far-end port */ - __be64 rx_pause; - /* Total number of microseconds that far-end port requested to pause - * transmission of packets - */ - __be64 rx_pause_duration; - /* Number of received transmission from XOFF state to XON state */ - __be64 rx_pause_transition; - /* Total number of PAUSE frames sent from the far-end port */ - __be64 tx_pause; - /* Total time in microseconds that transmission of packets has been - * paused - */ - __be64 tx_pause_duration; - /* Number of transmitter transitions from XOFF state to XON state */ - __be64 tx_pause_transition; - /* Reserverd */ - __be64 reserved[2]; -}; - -int mlx4_get_vport_ethtool_stats(struct mlx4_dev *dev, int port, - struct mlx4_en_vport_stats *vport_stats, - int reset); - -#define NUM_ALL_STATS (NUM_PKT_STATS + NUM_FLOW_STATS + NUM_VPORT_STATS + \ - NUM_VF_STATS + NUM_PORT_STATS + NUM_PERF_STATS) -#endif diff --git a/sys/ofed/drivers/net/mlx4/mr.c b/sys/ofed/drivers/net/mlx4/mr.c deleted file mode 100644 index 876d16dba1a3..000000000000 --- a/sys/ofed/drivers/net/mlx4/mr.c +++ /dev/null @@ -1,996 +0,0 @@ -/* - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> - -#include <linux/mlx4/cmd.h> - -#include <linux/math64.h> - -#include "mlx4.h" -#include "icm.h" - -static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) -{ - int o; - int m; - u32 seg; - - spin_lock(&buddy->lock); - - for (o = order; o <= buddy->max_order; ++o) - if (buddy->num_free[o]) { - m = 1 << (buddy->max_order - o); - seg = find_first_bit(buddy->bits[o], m); - if (seg < m) - goto found; - } - - spin_unlock(&buddy->lock); - return -1; - - found: - clear_bit(seg, buddy->bits[o]); - --buddy->num_free[o]; - - while (o > order) { - --o; - seg <<= 1; - set_bit(seg ^ 1, buddy->bits[o]); - ++buddy->num_free[o]; - } - - spin_unlock(&buddy->lock); - - seg <<= order; - - return seg; -} - -static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order) -{ - seg >>= order; - - spin_lock(&buddy->lock); - - while (test_bit(seg ^ 1, buddy->bits[order])) { - clear_bit(seg ^ 1, buddy->bits[order]); - --buddy->num_free[order]; - seg >>= 1; - ++order; - } - - set_bit(seg, buddy->bits[order]); - ++buddy->num_free[order]; - - spin_unlock(&buddy->lock); -} - -static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order) -{ - int i, s; - - buddy->max_order = max_order; - spin_lock_init(&buddy->lock); - - buddy->bits = kcalloc(buddy->max_order + 1, sizeof (long *), - GFP_KERNEL); - buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free, - GFP_KERNEL); - if (!buddy->bits || !buddy->num_free) - goto err_out; - - for (i = 0; i <= buddy->max_order; ++i) { - s = BITS_TO_LONGS(1 << (buddy->max_order - i)); - buddy->bits[i] = kcalloc(s, sizeof (long), GFP_KERNEL | __GFP_NOWARN); - if (!buddy->bits[i]) - goto err_out_free; - } - - set_bit(0, buddy->bits[buddy->max_order]); - buddy->num_free[buddy->max_order] = 1; - - return 0; - -err_out_free: - for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); - -err_out: - kfree(buddy->bits); - kfree(buddy->num_free); - - return -ENOMEM; -} - -static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) -{ - int i; - - for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); - - kfree(buddy->bits); - kfree(buddy->num_free); -} - -u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - u32 seg; - int seg_order; - u32 offset; - - seg_order = max_t(int, order - log_mtts_per_seg, 0); - - seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, seg_order); - if (seg == -1) - return -1; - - offset = seg * (1 << log_mtts_per_seg); - - if (mlx4_table_get_range(dev, &mr_table->mtt_table, offset, - offset + (1 << order) - 1)) { - mlx4_buddy_free(&mr_table->mtt_buddy, seg, seg_order); - return -1; - } - - return offset; -} - -static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) -{ - u64 in_param = 0; - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, order); - err = mlx4_cmd_imm(dev, in_param, &out_param, RES_MTT, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (err) - return -1; - return get_param_l(&out_param); - } - return __mlx4_alloc_mtt_range(dev, order); -} - -int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, - struct mlx4_mtt *mtt) -{ - int i; - - if (!npages) { - mtt->order = -1; - mtt->page_shift = MLX4_ICM_PAGE_SHIFT; - return 0; - } else - mtt->page_shift = page_shift; - - for (mtt->order = 0, i = 1; i < npages; i <<= 1) - ++mtt->order; - - mtt->offset = mlx4_alloc_mtt_range(dev, mtt->order); - if (mtt->offset == -1) { - mlx4_err(dev, "Failed to allocate mtts for %d pages(order %d)\n", - npages, mtt->order); - return -ENOMEM; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mtt_init); - -void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order) -{ - u32 first_seg; - int seg_order; - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - seg_order = max_t(int, order - log_mtts_per_seg, 0); - first_seg = offset / (1 << log_mtts_per_seg); - - mlx4_buddy_free(&mr_table->mtt_buddy, first_seg, seg_order); - mlx4_table_put_range(dev, &mr_table->mtt_table, offset, - offset + (1 << order) - 1); -} - -static void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, offset); - set_param_h(&in_param, order); - err = mlx4_cmd(dev, in_param, RES_MTT, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to free mtt range at:" - "%d order:%d\n", offset, order); - return; - } - __mlx4_free_mtt_range(dev, offset, order); -} - -void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) -{ - if (mtt->order < 0) - return; - - mlx4_free_mtt_range(dev, mtt->offset, mtt->order); -} -EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); - -u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt) -{ - return (u64) mtt->offset * dev->caps.mtt_entry_sz; -} -EXPORT_SYMBOL_GPL(mlx4_mtt_addr); - -static u32 hw_index_to_key(u32 ind) -{ - return (ind >> 24) | (ind << 8); -} - -static u32 key_to_hw_index(u32 key) -{ - return (key << 24) | (key >> 8); -} - -static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int mpt_index) -{ - return mlx4_cmd(dev, mailbox->dma, mpt_index, - 0, MLX4_CMD_SW2HW_MPT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int mpt_index) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, - !mailbox, MLX4_CMD_HW2SW_MPT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); -} - -static int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, - u64 iova, u64 size, u32 access, int npages, - int page_shift, struct mlx4_mr *mr) -{ - mr->iova = iova; - mr->size = size; - mr->pd = pd; - mr->access = access; - mr->enabled = MLX4_MPT_DISABLED; - mr->key = hw_index_to_key(mridx); - - return mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); -} - -static int mlx4_WRITE_MTT(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox, - int num_entries) -{ - return mlx4_cmd(dev, mailbox->dma, num_entries, 0, MLX4_CMD_WRITE_MTT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int __mlx4_mpt_reserve(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); -} - -static int mlx4_mpt_reserve(struct mlx4_dev *dev) -{ - u64 out_param; - - if (mlx4_is_mfunc(dev)) { - if (mlx4_cmd_imm(dev, 0, &out_param, RES_MPT, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - return -1; - return get_param_l(&out_param); - } - return __mlx4_mpt_reserve(dev); -} - -void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index, MLX4_NO_RR); -} - -static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, index); - if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_RESERVE, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to release mr index:%d\n", - index); - return; - } - __mlx4_mpt_release(dev, index); -} - -int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - return mlx4_table_get(dev, &mr_table->dmpt_table, index); -} - -static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) -{ - u64 param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(¶m, index); - return mlx4_cmd_imm(dev, param, ¶m, RES_MPT, RES_OP_MAP_ICM, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - } - return __mlx4_mpt_alloc_icm(dev, index); -} - -void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - mlx4_table_put(dev, &mr_table->dmpt_table, index); -} - -static void mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, index); - if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_MAP_ICM, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to free icm of mr index:%d\n", - index); - return; - } - return __mlx4_mpt_free_icm(dev, index); -} - -int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, - int npages, int page_shift, struct mlx4_mr *mr) -{ - u32 index; - int err; - - index = mlx4_mpt_reserve(dev); - if (index == -1) - return -ENOMEM; - - err = mlx4_mr_alloc_reserved(dev, index, pd, iova, size, - access, npages, page_shift, mr); - if (err) - mlx4_mpt_release(dev, index); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mr_alloc); - -static int mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - int err; - - if (mr->enabled == MLX4_MPT_EN_HW) { - err = mlx4_HW2SW_MPT(dev, NULL, - key_to_hw_index(mr->key) & - (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "HW2SW_MPT failed (%d).", err); - mlx4_warn(dev, "Most likely the MR has MWs bound to it.\n"); - return err; - } - - mr->enabled = MLX4_MPT_EN_SW; - } - mlx4_mtt_cleanup(dev, &mr->mtt); - - return 0; -} - -int mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - int ret; - - ret = mlx4_mr_free_reserved(dev, mr); - if (ret) - return ret; - if (mr->enabled) - mlx4_mpt_free_icm(dev, key_to_hw_index(mr->key)); - mlx4_mpt_release(dev, key_to_hw_index(mr->key)); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mr_free); - -int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mpt_entry *mpt_entry; - int err; - - err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key)); - if (err) - return err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_table; - } - mpt_entry = mailbox->buf; - - memset(mpt_entry, 0, sizeof *mpt_entry); - - mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO | - MLX4_MPT_FLAG_REGION | - mr->access); - - mpt_entry->key = cpu_to_be32(key_to_hw_index(mr->key)); - mpt_entry->pd_flags = cpu_to_be32(mr->pd | MLX4_MPT_PD_FLAG_EN_INV); - mpt_entry->start = cpu_to_be64(mr->iova); - mpt_entry->length = cpu_to_be64(mr->size); - mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); - - if (mr->mtt.order < 0) { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); - mpt_entry->mtt_addr = 0; - } else { - mpt_entry->mtt_addr = cpu_to_be64(mlx4_mtt_addr(dev, - &mr->mtt)); - } - - if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { - /* fast register MR in free state */ - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | - MLX4_MPT_PD_FLAG_RAE); - mpt_entry->mtt_sz = cpu_to_be32(1 << mr->mtt.order); - } else { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); - } - - err = mlx4_SW2HW_MPT(dev, mailbox, - key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); - goto err_cmd; - } - mr->enabled = MLX4_MPT_EN_HW; - - mlx4_free_cmd_mailbox(dev, mailbox); - - return 0; - -err_cmd: - mlx4_free_cmd_mailbox(dev, mailbox); - -err_table: - mlx4_mpt_free_icm(dev, key_to_hw_index(mr->key)); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mr_enable); - -static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - __be64 *mtts; - dma_addr_t dma_handle; - int i; - - mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->offset + - start_index, &dma_handle); - - if (!mtts) - return -ENOMEM; - - dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, - npages * sizeof (u64), DMA_TO_DEVICE); - - for (i = 0; i < npages; ++i) - mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - - dma_sync_single_for_device(&dev->pdev->dev, dma_handle, - npages * sizeof (u64), DMA_TO_DEVICE); - - return 0; -} - -int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - int err = 0; - int chunk; - int mtts_per_page; - int max_mtts_first_page; - - /* compute how may mtts fit in the first page */ - mtts_per_page = PAGE_SIZE / sizeof(u64); - max_mtts_first_page = mtts_per_page - (mtt->offset + start_index) - % mtts_per_page; - - chunk = min_t(int, max_mtts_first_page, npages); - - while (npages > 0) { - err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); - if (err) - return err; - npages -= chunk; - start_index += chunk; - page_list += chunk; - - chunk = min_t(int, mtts_per_page, npages); - } - return err; -} - -int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - struct mlx4_cmd_mailbox *mailbox = NULL; - __be64 *inbox = NULL; - int chunk; - int err = 0; - int i; - - if (mtt->order < 0) - return -EINVAL; - - if (mlx4_is_mfunc(dev)) { - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - while (npages > 0) { - chunk = min_t(int, MLX4_MAILBOX_SIZE / sizeof(u64) - 2, - npages); - inbox[0] = cpu_to_be64(mtt->offset + start_index); - inbox[1] = 0; - for (i = 0; i < chunk; ++i) - inbox[i + 2] = cpu_to_be64(page_list[i] | - MLX4_MTT_FLAG_PRESENT); - err = mlx4_WRITE_MTT(dev, mailbox, chunk); - if (err) { - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - } - - npages -= chunk; - start_index += chunk; - page_list += chunk; - } - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - } - - return __mlx4_write_mtt(dev, mtt, start_index, npages, page_list); -} -EXPORT_SYMBOL_GPL(mlx4_write_mtt); - -int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_buf *buf) -{ - u64 *page_list; - int err; - int i; - - page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); - if (!page_list) - return -ENOMEM; - - for (i = 0; i < buf->npages; ++i) - if (buf->nbufs == 1) - page_list[i] = buf->direct.map + (i << buf->page_shift); - else - page_list[i] = buf->page_list[i].map; - - err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list); - - kfree(page_list); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); - -int mlx4_mw_alloc(struct mlx4_dev *dev, u32 pd, enum mlx4_mw_type type, - struct mlx4_mw *mw) -{ - u32 index; - - index = mlx4_mpt_reserve(dev); - if (index == -1) - return -ENOMEM; - - mw->key = hw_index_to_key(index); - mw->pd = pd; - mw->type = type; - mw->enabled = MLX4_MPT_DISABLED; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mw_alloc); - -int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mpt_entry *mpt_entry; - int err; - - err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key)); - if (err) - return err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_table; - } - mpt_entry = mailbox->buf; - - memset(mpt_entry, 0, sizeof(*mpt_entry)); - - /* Note that the MLX4_MPT_FLAG_REGION bit in mpt_entry->flags is turned - * off, thus creating a memory window and not a memory region. - */ - mpt_entry->key = cpu_to_be32(key_to_hw_index(mw->key)); - mpt_entry->pd_flags = cpu_to_be32(mw->pd); - if (mw->type == MLX4_MW_TYPE_2) { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->qpn = cpu_to_be32(MLX4_MPT_QP_FLAG_BOUND_QP); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_EN_INV); - } - - err = mlx4_SW2HW_MPT(dev, mailbox, - key_to_hw_index(mw->key) & - (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); - goto err_cmd; - } - mw->enabled = MLX4_MPT_EN_HW; - - mlx4_free_cmd_mailbox(dev, mailbox); - - return 0; - -err_cmd: - mlx4_free_cmd_mailbox(dev, mailbox); - -err_table: - mlx4_mpt_free_icm(dev, key_to_hw_index(mw->key)); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mw_enable); - -void mlx4_mw_free(struct mlx4_dev *dev, struct mlx4_mw *mw) -{ - int err; - - if (mw->enabled == MLX4_MPT_EN_HW) { - err = mlx4_HW2SW_MPT(dev, NULL, - key_to_hw_index(mw->key) & - (dev->caps.num_mpts - 1)); - if (err) - mlx4_warn(dev, "xxx HW2SW_MPT failed (%d)\n", err); - - mw->enabled = MLX4_MPT_EN_SW; - } - if (mw->enabled) - mlx4_mpt_free_icm(dev, key_to_hw_index(mw->key)); - mlx4_mpt_release(dev, key_to_hw_index(mw->key)); -} -EXPORT_SYMBOL_GPL(mlx4_mw_free); - -int mlx4_init_mr_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_mr_table *mr_table = &priv->mr_table; - int err; - - /* Nothing to do for slaves - all MR handling is forwarded - * to the master */ - if (mlx4_is_slave(dev)) - return 0; - - if (!is_power_of_2(dev->caps.num_mpts)) - return -EINVAL; - - err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, - ~0, dev->caps.reserved_mrws, 0); - if (err) - return err; - - err = mlx4_buddy_init(&mr_table->mtt_buddy, - ilog2(div_u64(dev->caps.num_mtts, - (1 << log_mtts_per_seg)))); - if (err) - goto err_buddy; - - if (dev->caps.reserved_mtts) { - priv->reserved_mtts = - mlx4_alloc_mtt_range(dev, - fls(dev->caps.reserved_mtts - 1)); - if (priv->reserved_mtts < 0) { - mlx4_warn(dev, "MTT table of order %u is too small.\n", - mr_table->mtt_buddy.max_order); - err = -ENOMEM; - goto err_reserve_mtts; - } - } - - return 0; - -err_reserve_mtts: - mlx4_buddy_cleanup(&mr_table->mtt_buddy); - -err_buddy: - mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); - - return err; -} - -void mlx4_cleanup_mr_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_mr_table *mr_table = &priv->mr_table; - - if (mlx4_is_slave(dev)) - return; - if (priv->reserved_mtts >= 0) - mlx4_free_mtt_range(dev, priv->reserved_mtts, - fls(dev->caps.reserved_mtts - 1)); - mlx4_buddy_cleanup(&mr_table->mtt_buddy); - mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); -} - -static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, - int npages, u64 iova) -{ - int i, page_mask; - - if (npages > fmr->max_pages) - return -EINVAL; - - page_mask = (1 << fmr->page_shift) - 1; - - /* We are getting page lists, so va must be page aligned. */ - if (iova & page_mask) - return -EINVAL; - - /* Trust the user not to pass misaligned data in page_list */ - if (0) - for (i = 0; i < npages; ++i) { - if (page_list[i] & ~page_mask) - return -EINVAL; - } - - if (fmr->maps >= fmr->max_maps) - return -EINVAL; - - return 0; -} - -int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, - int npages, u64 iova, u32 *lkey, u32 *rkey) -{ - u32 key; - int i, err; - - err = mlx4_check_fmr(fmr, page_list, npages, iova); - if (err) - return err; - - ++fmr->maps; - - key = key_to_hw_index(fmr->mr.key); - key += dev->caps.num_mpts; - *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); - - *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; - - /* Make sure MPT status is visible before writing MTT entries */ - wmb(); - - dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); - - for (i = 0; i < npages; ++i) - fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - - dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); - - fmr->mpt->key = cpu_to_be32(key); - fmr->mpt->lkey = cpu_to_be32(key); - fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); - fmr->mpt->start = cpu_to_be64(iova); - - /* Make MTT entries are visible before setting MPT status */ - wmb(); - - *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; - - /* Make sure MPT status is visible before consumer can use FMR */ - wmb(); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); - -int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, - int max_maps, u8 page_shift, struct mlx4_fmr *fmr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err = -ENOMEM, ret; - - if (max_maps > dev->caps.max_fmr_maps) - return -EINVAL; - - if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) - return -EINVAL; - - /* All MTTs must fit in the same page */ - if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) - return -EINVAL; - - fmr->page_shift = page_shift; - fmr->max_pages = max_pages; - fmr->max_maps = max_maps; - fmr->maps = 0; - - err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, - page_shift, &fmr->mr); - if (err) - return err; - - fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, - fmr->mr.mtt.offset, - &fmr->dma_handle); - - if (!fmr->mtts) { - err = -ENOMEM; - goto err_free; - } - - return 0; - -err_free: - ret = mlx4_mr_free(dev, &fmr->mr); - if (ret) - mlx4_err(dev, "Error deregistering MR. The system may have become unstable."); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); - -int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - - err = mlx4_mr_enable(dev, &fmr->mr); - if (err) - return err; - - fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, - key_to_hw_index(fmr->mr.key), NULL); - if (!fmr->mpt) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_enable); - -void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, - u32 *lkey, u32 *rkey) -{ - u32 key; - - if (!fmr->maps) - return; - - key = key_to_hw_index(fmr->mr.key) & (dev->caps.num_mpts - 1); - - *(u8 *)fmr->mpt = MLX4_MPT_STATUS_SW; - - /* Make sure MPT status is visible before changing MPT fields */ - wmb(); - - fmr->mr.key = hw_index_to_key(key); - - fmr->mpt->key = cpu_to_be32(key); - fmr->mpt->lkey = cpu_to_be32(key); - fmr->mpt->length = 0; - fmr->mpt->start = 0; - - /* Make sure MPT data is visible before changing MPT status */ - wmb(); - - *(u8 *)fmr->mpt = MLX4_MPT_STATUS_HW; - - /* Make sure MPT satus is visible */ - wmb(); - - fmr->maps = 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); - -int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) -{ - int ret; - - if (fmr->maps) - return -EBUSY; - - ret = mlx4_mr_free(dev, &fmr->mr); - if (ret) - return ret; - fmr->mr.enabled = MLX4_MPT_DISABLED; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_free); - -int mlx4_SYNC_TPT(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, - MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/sys/ofed/drivers/net/mlx4/pd.c b/sys/ofed/drivers/net/mlx4/pd.c deleted file mode 100644 index 89a8854699ac..000000000000 --- a/sys/ofed/drivers/net/mlx4/pd.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/io-mapping.h> - -#include <linux/page.h> - -#include "mlx4.h" -#include "icm.h" - -enum { - MLX4_NUM_RESERVED_UARS = 8 -}; - -int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); - if (*pdn == -1) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_pd_alloc); - -void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn, MLX4_USE_RR); -} -EXPORT_SYMBOL_GPL(mlx4_pd_free); - -int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - *xrcdn = mlx4_bitmap_alloc(&priv->xrcd_bitmap); - if (*xrcdn == -1) - return -ENOMEM; - - return 0; -} - -int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, - RES_XRCD, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - - *xrcdn = get_param_l(&out_param); - return 0; - } - return __mlx4_xrcd_alloc(dev, xrcdn); -} -EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); - -void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn, MLX4_USE_RR); -} - -void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, xrcdn); - err = mlx4_cmd(dev, in_param, RES_XRCD, - RES_OP_RESERVE, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to release xrcdn %d\n", xrcdn); - } else - __mlx4_xrcd_free(dev, xrcdn); -} -EXPORT_SYMBOL_GPL(mlx4_xrcd_free); - -int mlx4_init_pd_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds, - (1 << NOT_MASKED_PD_BITS) - 1, - dev->caps.reserved_pds, 0); -} - -void mlx4_cleanup_pd_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap); -} - -int mlx4_init_xrcd_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_init(&priv->xrcd_bitmap, (1 << 16), - (1 << 16) - 1, dev->caps.reserved_xrcds + 1, 0); -} - -void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->xrcd_bitmap); -} - -int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) -{ - int offset; - - uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap); - if (uar->index == -1) - return -ENOMEM; - - if (mlx4_is_slave(dev)) - offset = uar->index % ((int) pci_resource_len(dev->pdev, 2) / - dev->caps.uar_page_size); - else - offset = uar->index; - uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + offset; - uar->map = NULL; - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_uar_alloc); - -void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index, MLX4_USE_RR); -} -EXPORT_SYMBOL_GPL(mlx4_uar_free); - -#ifndef CONFIG_PPC -int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_uar *uar; - int err = 0; - int idx; - - if (!priv->bf_mapping) - return -ENOMEM; - - mutex_lock(&priv->bf_mutex); - if (!list_empty(&priv->bf_list)) - uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); - else { - if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { - err = -ENOMEM; - goto out; - } - uar = kmalloc_node(sizeof *uar, GFP_KERNEL, node); - if (!uar) { - uar = kmalloc(sizeof *uar, GFP_KERNEL); - if (!uar) { - err = -ENOMEM; - goto out; - } - } - err = mlx4_uar_alloc(dev, uar); - if (err) - goto free_kmalloc; - - uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); - if (!uar->map) { - err = -ENOMEM; - goto free_uar; - } - - uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); - if (!uar->bf_map) { - err = -ENOMEM; - goto unamp_uar; - } - uar->free_bf_bmap = 0; - list_add(&uar->bf_list, &priv->bf_list); - } - - bf->uar = uar; - idx = ffz(uar->free_bf_bmap); - uar->free_bf_bmap |= 1 << idx; - bf->uar = uar; - bf->offset = 0; - bf->buf_size = dev->caps.bf_reg_size / 2; - bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; - if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) - list_del_init(&uar->bf_list); - - goto out; - -unamp_uar: - bf->uar = NULL; - iounmap(uar->map); - -free_uar: - mlx4_uar_free(dev, uar); - -free_kmalloc: - kfree(uar); - -out: - mutex_unlock(&priv->bf_mutex); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_bf_alloc); - -void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int idx; - - if (!bf->uar || !bf->uar->bf_map) - return; - - mutex_lock(&priv->bf_mutex); - idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; - bf->uar->free_bf_bmap &= ~(1 << idx); - if (!bf->uar->free_bf_bmap) { - if (!list_empty(&bf->uar->bf_list)) - list_del(&bf->uar->bf_list); - - io_mapping_unmap(bf->uar->bf_map); - iounmap(bf->uar->map); - mlx4_uar_free(dev, bf->uar); - kfree(bf->uar); - } else if (list_empty(&bf->uar->bf_list)) - list_add(&bf->uar->bf_list, &priv->bf_list); - - mutex_unlock(&priv->bf_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_bf_free); - -#else -int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) -{ - memset(bf, 0, sizeof *bf); - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(mlx4_bf_alloc); - -void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) -{ - return; -} -EXPORT_SYMBOL_GPL(mlx4_bf_free); -#endif - -int mlx4_init_uar_table(struct mlx4_dev *dev) -{ - if (dev->caps.num_uars <= 128) { - mlx4_err(dev, "Only %d UAR pages (need more than 128)\n", - dev->caps.num_uars); - mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n"); - return -ENODEV; - } - - return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap, - dev->caps.num_uars, dev->caps.num_uars - 1, - dev->caps.reserved_uars, 0); -} - -void mlx4_cleanup_uar_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/port.c b/sys/ofed/drivers/net/mlx4/port.c deleted file mode 100644 index aeb38746cbd5..000000000000 --- a/sys/ofed/drivers/net/mlx4/port.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/errno.h> -#include <linux/if_ether.h> -#include <linux/module.h> -#include <linux/err.h> - -#include <linux/mlx4/cmd.h> -#include <linux/moduleparam.h> -#include "mlx4.h" -#include "mlx4_stats.h" - - -int mlx4_set_4k_mtu = -1; -module_param_named(set_4k_mtu, mlx4_set_4k_mtu, int, 0444); -MODULE_PARM_DESC(set_4k_mtu, - "(Obsolete) attempt to set 4K MTU to all ConnectX ports"); - - -#define MLX4_MAC_VALID (1ull << 63) - -#define MLX4_VLAN_VALID (1u << 31) -#define MLX4_VLAN_MASK 0xfff - -void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) -{ - int i; - - mutex_init(&table->mutex); - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - table->entries[i] = 0; - table->refs[i] = 0; - } - table->max = 1 << dev->caps.log_num_macs; - table->total = 0; -} - -void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) -{ - int i; - - mutex_init(&table->mutex); - for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { - table->entries[i] = 0; - table->refs[i] = 0; - } - table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; - table->total = 0; -} - -static int validate_index(struct mlx4_dev *dev, - struct mlx4_mac_table *table, int index) -{ - int err = 0; - - if (index < 0 || index >= table->max || !table->refs[index]) { - mlx4_warn(dev, "No valid Mac entry for the given index\n"); - err = -EINVAL; - } - return err; -} - -static int find_index(struct mlx4_dev *dev, - struct mlx4_mac_table *table, u64 mac) -{ - int i; - - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - if ((mac & MLX4_MAC_MASK) == - (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) - return i; - } - /* Mac not found */ - return -EINVAL; -} - -static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, - __be64 *entries) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 in_mod; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); - - in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; - - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - struct mlx4_mac_table *table = &info->mac_table; - int i, err = 0; - int free = -1; - - mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", - (unsigned long long) mac, port); - - mutex_lock(&table->mutex); - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - if (free < 0 && !table->refs[i]) { - free = i; - continue; - } - - if ((mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) && - table->refs[i]) { - /* MAC already registered, Must not have duplicates */ - err = i; - ++table->refs[i]; - goto out; - } - } - - mlx4_dbg(dev, "Free MAC index is %d\n", free); - - if (table->total == table->max) { - /* No free mac entries */ - err = -ENOSPC; - goto out; - } - - /* Register new MAC */ - table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); - - err = mlx4_set_port_mac_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_err(dev, "Failed adding MAC: 0x%llx\n", - (unsigned long long) mac); - table->entries[free] = 0; - goto out; - } - table->refs[free] = 1; - - err = free; - ++table->total; -out: - mutex_unlock(&table->mutex); - return err; -} -EXPORT_SYMBOL_GPL(__mlx4_register_mac); - -int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - u64 out_param = 0; - int err = -EINVAL; - - if (mlx4_is_mfunc(dev)) { - if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { - err = mlx4_cmd_imm(dev, mac, &out_param, - ((u32) port) << 8 | (u32) RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } - if (err && err == -EINVAL && mlx4_is_slave(dev)) { - /* retry using old REG_MAC format */ - set_param_l(&out_param, port); - err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - dev->flags |= MLX4_FLAG_OLD_REG_MAC; - } - if (err) - return err; - - return get_param_l(&out_param); - } - return __mlx4_register_mac(dev, port, mac); -} -EXPORT_SYMBOL_GPL(mlx4_register_mac); - -int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) -{ - return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + - (port - 1) * (1 << dev->caps.log_num_macs); -} -EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); - -void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - struct mlx4_port_info *info; - struct mlx4_mac_table *table; - int index; - - if (port < 1 || port > dev->caps.num_ports) { - mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); - return; - } - info = &mlx4_priv(dev)->port[port]; - table = &info->mac_table; - mutex_lock(&table->mutex); - - index = find_index(dev, table, mac); - - if (validate_index(dev, table, index)) - goto out; - - if (--table->refs[index]) { - mlx4_dbg(dev, "Have more references for index %d," - "no need to modify mac table\n", index); - goto out; - } - - table->entries[index] = 0; - mlx4_set_port_mac_table(dev, port, table->entries); - --table->total; -out: - mutex_unlock(&table->mutex); -} -EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); - -void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - u64 out_param = 0; - - if (mlx4_is_mfunc(dev)) { - if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { - (void) mlx4_cmd_imm(dev, mac, &out_param, - ((u32) port) << 8 | (u32) RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } else { - /* use old unregister mac format */ - set_param_l(&out_param, port); - (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } - return; - } - __mlx4_unregister_mac(dev, port, mac); - return; -} -EXPORT_SYMBOL_GPL(mlx4_unregister_mac); - -int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - struct mlx4_mac_table *table = &info->mac_table; - int index = qpn - info->base_qpn; - int err = 0; - - /* CX1 doesn't support multi-functions */ - mutex_lock(&table->mutex); - - err = validate_index(dev, table, index); - if (err) - goto out; - - table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); - - err = mlx4_set_port_mac_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_err(dev, "Failed adding MAC: 0x%llx\n", - (unsigned long long) new_mac); - table->entries[index] = 0; - } -out: - mutex_unlock(&table->mutex); - return err; -} -EXPORT_SYMBOL_GPL(__mlx4_replace_mac); - -static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, - __be32 *entries) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 in_mod; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); - in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; -} - -int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int i; - - for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { - if (table->refs[i] && - (vid == (MLX4_VLAN_MASK & - be32_to_cpu(table->entries[i])))) { - /* VLAN already registered, increase reference count */ - *idx = i; - return 0; - } - } - - return -ENOENT; -} -EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); - -int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, - int *index) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int i, err = 0; - int free = -1; - - mutex_lock(&table->mutex); - - if (table->total == table->max) { - /* No free vlan entries */ - err = -ENOSPC; - goto out; - } - - for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { - if (free < 0 && (table->refs[i] == 0)) { - free = i; - continue; - } - - if (table->refs[i] && - (vlan == (MLX4_VLAN_MASK & - be32_to_cpu(table->entries[i])))) { - /* Vlan already registered, increase references count */ - *index = i; - ++table->refs[i]; - goto out; - } - } - - if (free < 0) { - err = -ENOMEM; - goto out; - } - - /* Register new VLAN */ - table->refs[free] = 1; - table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); - - err = mlx4_set_port_vlan_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); - table->refs[free] = 0; - table->entries[free] = 0; - goto out; - } - - *index = free; - ++table->total; -out: - mutex_unlock(&table->mutex); - return err; -} - -int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) -{ - u64 out_param = 0; - int err; - - if (vlan > 4095) - return -EINVAL; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, vlan, &out_param, - ((u32) port) << 8 | (u32) RES_VLAN, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - *index = get_param_l(&out_param); - - return err; - } - return __mlx4_register_vlan(dev, port, vlan, index); -} -EXPORT_SYMBOL_GPL(mlx4_register_vlan); - -void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int index; - - mutex_lock(&table->mutex); - if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { - mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); - goto out; - } - - if (index < MLX4_VLAN_REGULAR) { - mlx4_warn(dev, "Trying to free special vlan index %d\n", index); - goto out; - } - - if (--table->refs[index]) { - mlx4_dbg(dev, "Have %d more references for index %d, " - "no need to modify vlan table\n", table->refs[index], - index); - goto out; - } - table->entries[index] = 0; - mlx4_set_port_vlan_table(dev, port, table->entries); - --table->total; -out: - mutex_unlock(&table->mutex); -} - -void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) -{ - u64 out_param = 0; - - if (mlx4_is_mfunc(dev)) { - (void) mlx4_cmd_imm(dev, vlan, &out_param, - ((u32) port) << 8 | (u32) RES_VLAN, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - return; - } - __mlx4_unregister_vlan(dev, port, vlan); -} -EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); - -int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) -{ - struct mlx4_cmd_mailbox *inmailbox, *outmailbox; - u8 *inbuf, *outbuf; - int err; - - inmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inmailbox)) - return PTR_ERR(inmailbox); - - outmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outmailbox)) { - mlx4_free_cmd_mailbox(dev, inmailbox); - return PTR_ERR(outmailbox); - } - - inbuf = inmailbox->buf; - outbuf = outmailbox->buf; - memset(inbuf, 0, 256); - memset(outbuf, 0, 256); - inbuf[0] = 1; - inbuf[1] = 1; - inbuf[2] = 1; - inbuf[3] = 1; - *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); - *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); - - err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (!err) - *caps = *(__be32 *) (outbuf + 84); - mlx4_free_cmd_mailbox(dev, inmailbox); - mlx4_free_cmd_mailbox(dev, outmailbox); - return err; -} -static struct mlx4_roce_gid_entry zgid_entry; - -int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave) -{ - if (slave == 0) - return MLX4_ROCE_PF_GIDS; - if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs)) - return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1; - return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs; -} - -int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave) -{ - int gids; - int vfs; - - gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - vfs = dev->num_vfs; - - if (slave == 0) - return 0; - if (slave <= gids % vfs) - return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); - - return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); -} - -static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, - u8 op_mod, struct mlx4_cmd_mailbox *inbox) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_port_info *port_info; - struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; - struct mlx4_slave_state *slave_st = &master->slave_state[slave]; - struct mlx4_set_port_rqp_calc_context *qpn_context; - struct mlx4_set_port_general_context *gen_context; - struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; - int reset_qkey_viols; - int port; - int is_eth; - int num_gids; - int base; - u32 in_modifier; - u32 promisc; - u16 mtu, prev_mtu; - int err; - int i, j; - int offset; - __be32 agg_cap_mask; - __be32 slave_cap_mask; - __be32 new_cap_mask; - - port = in_mod & 0xff; - in_modifier = (in_mod >> 8) & 0xff; - is_eth = op_mod; - port_info = &priv->port[port]; - - if (op_mod > 1) - return -EINVAL; - - /* Slaves cannot perform SET_PORT operations except changing MTU */ - if (is_eth) { - if (slave != dev->caps.function && - in_modifier != MLX4_SET_PORT_GENERAL && - in_modifier != MLX4_SET_PORT_GID_TABLE) { - mlx4_warn(dev, "denying SET_PORT for slave:%d," - "port %d, config_select 0x%x\n", - slave, port, in_modifier); - return -EINVAL; - } - switch (in_modifier) { - case MLX4_SET_PORT_RQP_CALC: - qpn_context = inbox->buf; - qpn_context->base_qpn = - cpu_to_be32(port_info->base_qpn); - qpn_context->n_mac = 0x7; - promisc = be32_to_cpu(qpn_context->promisc) >> - SET_PORT_PROMISC_SHIFT; - qpn_context->promisc = cpu_to_be32( - promisc << SET_PORT_PROMISC_SHIFT | - port_info->base_qpn); - promisc = be32_to_cpu(qpn_context->mcast) >> - SET_PORT_MC_PROMISC_SHIFT; - qpn_context->mcast = cpu_to_be32( - promisc << SET_PORT_MC_PROMISC_SHIFT | - port_info->base_qpn); - break; - case MLX4_SET_PORT_GENERAL: - gen_context = inbox->buf; - /* Mtu is configured as the max MTU among all the - * the functions on the port. */ - mtu = be16_to_cpu(gen_context->mtu); - mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + - ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); - prev_mtu = slave_st->mtu[port]; - slave_st->mtu[port] = mtu; - if (mtu > master->max_mtu[port]) - master->max_mtu[port] = mtu; - if (mtu < prev_mtu && prev_mtu == - master->max_mtu[port]) { - slave_st->mtu[port] = mtu; - master->max_mtu[port] = mtu; - for (i = 0; i < dev->num_slaves; i++) { - master->max_mtu[port] = - max(master->max_mtu[port], - master->slave_state[i].mtu[port]); - } - } - - gen_context->mtu = cpu_to_be16(master->max_mtu[port]); - break; - case MLX4_SET_PORT_GID_TABLE: - /* change to MULTIPLE entries: number of guest's gids - * need a FOR-loop here over number of gids the guest has. - * 1. Check no duplicates in gids passed by slave - */ - num_gids = mlx4_get_slave_num_gids(dev, slave); - base = mlx4_get_base_gid_ix(dev, slave); - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0; i < num_gids; gid_entry_mbox++, i++) { - if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, - sizeof(zgid_entry))) - continue; - gid_entry_mb1 = gid_entry_mbox + 1; - for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { - if (!memcmp(gid_entry_mb1->raw, - zgid_entry.raw, sizeof(zgid_entry))) - continue; - if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, - sizeof(gid_entry_mbox->raw))) { - /* found duplicate */ - return -EINVAL; - } - } - } - - /* 2. Check that do not have duplicates in OTHER - * entries in the port GID table - */ - for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - if (i >= base && i < base + num_gids) - continue; /* don't compare to slave's current gids */ - gid_entry_tbl = &priv->roce_gids[port - 1][i]; - if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) - continue; - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (j = 0; j < num_gids; gid_entry_mbox++, j++) { - if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, - sizeof(zgid_entry))) - continue; - if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, - sizeof(gid_entry_tbl->raw))) { - /* found duplicate */ - mlx4_warn(dev, "requested gid entry for slave:%d " - "is a duplicate of gid at index %d\n", - slave, i); - return -EINVAL; - } - } - } - - /* insert slave GIDs with memcpy, starting at slave's base index */ - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) - memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16); - - /* Now, copy roce port gids table to current mailbox for passing to FW */ - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) - memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16); - - break; - } - return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, - MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - } - - /* For IB, we only consider: - * - The capability mask, which is set to the aggregate of all - * slave function capabilities - * - The QKey violatin counter - reset according to each request. - */ - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; - new_cap_mask = ((__be32 *) inbox->buf)[2]; - } else { - reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; - new_cap_mask = ((__be32 *) inbox->buf)[1]; - } - - /* slave may not set the IS_SM capability for the port */ - if (slave != mlx4_master_func_num(dev) && - (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) - return -EINVAL; - - /* No DEV_MGMT in multifunc mode */ - if (mlx4_is_mfunc(dev) && - (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) - return -EINVAL; - - agg_cap_mask = 0; - slave_cap_mask = - priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; - priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; - for (i = 0; i < dev->num_slaves; i++) - agg_cap_mask |= - priv->mfunc.master.slave_state[i].ib_cap_mask[port]; - - /* only clear mailbox for guests. Master may be setting - * MTU or PKEY table size - */ - if (slave != dev->caps.function) - memset(inbox->buf, 0, 256); - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; - ((__be32 *) inbox->buf)[2] = agg_cap_mask; - } else { - ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; - ((__be32 *) inbox->buf)[1] = agg_cap_mask; - } - - err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = - slave_cap_mask; - return err; -} - -int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return mlx4_common_set_port(dev, slave, vhcr->in_modifier, - vhcr->op_modifier, inbox); -} - -/* bit locations for set port command with zero op modifier */ -enum { - MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ - MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ - MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, - MLX4_CHANGE_PORT_VL_CAP = 21, - MLX4_CHANGE_PORT_MTU_CAP = 22, -}; - -int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) -{ - struct mlx4_cmd_mailbox *mailbox; - int err = -EINVAL, vl_cap, pkey_tbl_flag = 0; - u32 in_mod; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_NONE) - return 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memset(mailbox->buf, 0, 256); - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { - in_mod = MLX4_SET_PORT_GENERAL << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, - MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - } else { - ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; - - if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { - pkey_tbl_flag = 1; - ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); - } - - /* IB VL CAP enum isn't used by the firmware, just numerical values */ - for (vl_cap = dev->caps.vl_cap[port]; - vl_cap >= 1; vl_cap >>= 1) { - ((__be32 *) mailbox->buf)[0] = cpu_to_be32( - (1 << MLX4_CHANGE_PORT_MTU_CAP) | - (1 << MLX4_CHANGE_PORT_VL_CAP) | - (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | - (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | - (vl_cap << MLX4_SET_PORT_VL_CAP)); - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - if (err != -ENOMEM) - break; - } - } - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, - u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_general_context *context; - int err; - u32 in_mod; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - context->flags = SET_PORT_GEN_ALL_VALID; - context->mtu = cpu_to_be16(mtu); - context->pptx = (pptx * (!pfctx)) << 7; - context->pfctx = pfctx; - context->pprx = (pprx * (!pfcrx)) << 7; - context->pfcrx = pfcrx; - - in_mod = MLX4_SET_PORT_GENERAL << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_general); - -int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, - u8 promisc) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_rqp_calc_context *context; - int err; - u32 in_mod; - u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? - MCAST_DIRECT : MCAST_DEFAULT; - - if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) - return 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - context->base_qpn = cpu_to_be32(base_qpn); - context->n_mac = dev->caps.log_num_macs; - context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | - base_qpn); - context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | - base_qpn); - context->intra_no_vlan = 0; - context->no_vlan = MLX4_NO_VLAN_IDX; - context->intra_vlan_miss = 0; - context->vlan_miss = MLX4_VLAN_MISS_IDX; - - in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); - -int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_prio2tc_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - for (i = 0; i < MLX4_NUM_UP; i += 2) - context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; - - in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); - -int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, - u8 *pg, u16 *ratelimit) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_scheduler_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - for (i = 0; i < MLX4_NUM_TC; i++) { - struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; - u16 r; - if (ratelimit && ratelimit[i]) { - if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { - r = ratelimit[i]; - tc->max_bw_units = - htons(MLX4_RATELIMIT_100M_UNITS); - } else { - r = ratelimit[i]/10; - tc->max_bw_units = - htons(MLX4_RATELIMIT_1G_UNITS); - } - tc->max_bw_value = htons(r); - } else { - tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); - tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); - } - - tc->pg = htons(pg[i]); - tc->bw_precentage = htons(tc_tx_bw[i]); - } - - in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); - -int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = 0; - - return err; -} - -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, - u64 mac, u64 clear, u8 mode) -{ - return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, - MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} -EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); - -int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = 0; - - return err; -} - -int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return 0; -} - -void mlx4_set_stats_bitmap(struct mlx4_dev *dev, unsigned long *stats_bitmap) -{ - int last_i = 0; - - bitmap_zero(stats_bitmap, NUM_ALL_STATS); - - if (mlx4_is_slave(dev)) { - last_i = dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN ? - NUM_PKT_STATS + NUM_FLOW_STATS : NUM_PKT_STATS; - } else { - bitmap_set(stats_bitmap, last_i, NUM_PKT_STATS); - last_i = NUM_PKT_STATS; - - if (dev->caps.flags2 & - MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) { - bitmap_set(stats_bitmap, last_i, NUM_FLOW_STATS); - last_i += NUM_FLOW_STATS; - } - } - - if (mlx4_is_slave(dev)) - bitmap_set(stats_bitmap, last_i, NUM_VF_STATS); - last_i += NUM_VF_STATS; - - if (mlx4_is_master(dev)) - bitmap_set(stats_bitmap, last_i, NUM_VPORT_STATS); - last_i += NUM_VPORT_STATS; - - bitmap_set(stats_bitmap, last_i, NUM_PORT_STATS); -} -EXPORT_SYMBOL(mlx4_set_stats_bitmap); - -int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, found_ix = -1; - int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - - if (!mlx4_is_mfunc(dev)) - return -EINVAL; - - for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) { - found_ix = i; - break; - } - } - - if (found_ix >= 0) { - if (found_ix < MLX4_ROCE_PF_GIDS) - *slave_id = 0; - else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) * - (vf_gids / dev->num_vfs + 1)) - *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) / - (vf_gids / dev->num_vfs + 1)) + 1; - else - *slave_id = - ((found_ix - MLX4_ROCE_PF_GIDS - - ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) / - (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1; - } - - return (found_ix >= 0) ? 0 : -EINVAL; -} -EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); - -int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (!mlx4_is_master(dev)) - return -EINVAL; - - memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16); - return 0; -} -EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); - -/* Cable Module Info */ -#define MODULE_INFO_MAX_READ 48 - -#define I2C_ADDR_LOW 0x50 -#define I2C_ADDR_HIGH 0x51 -#define I2C_PAGE_SIZE 256 - -/* Module Info Data */ -struct mlx4_cable_info { - u8 i2c_addr; - u8 page_num; - __be16 dev_mem_address; - __be16 reserved1; - __be16 size; - __be32 reserved2[2]; - u8 data[MODULE_INFO_MAX_READ]; -}; - -enum cable_info_err { - CABLE_INF_INV_PORT = 0x1, - CABLE_INF_OP_NOSUP = 0x2, - CABLE_INF_NOT_CONN = 0x3, - CABLE_INF_NO_EEPRM = 0x4, - CABLE_INF_PAGE_ERR = 0x5, - CABLE_INF_INV_ADDR = 0x6, - CABLE_INF_I2C_ADDR = 0x7, - CABLE_INF_QSFP_VIO = 0x8, - CABLE_INF_I2C_BUSY = 0x9, -}; - -#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) - -#ifdef DEBUG -static inline const char *cable_info_mad_err_str(u16 mad_status) -{ - u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); - - switch (err) { - case CABLE_INF_INV_PORT: - return "invalid port selected"; - case CABLE_INF_OP_NOSUP: - return "operation not supported for this port (the port is of type CX4 or internal)"; - case CABLE_INF_NOT_CONN: - return "cable is not connected"; - case CABLE_INF_NO_EEPRM: - return "the connected cable has no EPROM (passive copper cable)"; - case CABLE_INF_PAGE_ERR: - return "page number is greater than 15"; - case CABLE_INF_INV_ADDR: - return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; - case CABLE_INF_I2C_ADDR: - return "invalid I2C slave address"; - case CABLE_INF_QSFP_VIO: - return "at least one cable violates the QSFP specification and ignores the modsel signal"; - case CABLE_INF_I2C_BUSY: - return "I2C bus is constantly busy"; - } - return "Unknown Error"; -} -#endif /* DEBUG */ - -/** - * mlx4_get_module_info - Read cable module eeprom data - * @dev: mlx4_dev. - * @port: port number. - * @offset: byte offset in eeprom to start reading data from. - * @size: num of bytes to read. - * @data: output buffer to put the requested data into. - * - * Reads cable module eeprom data, puts the outcome data into - * data pointer paramer. - * Returns num of read bytes on success or a negative error - * code. - */ -int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset, - u16 size, u8 *data) -{ - struct mlx4_cmd_mailbox *inbox, *outbox; - struct mlx4_mad_ifc *inmad, *outmad; - struct mlx4_cable_info *cable_info; - u16 i2c_addr; - int ret; - - if (size > MODULE_INFO_MAX_READ) - size = MODULE_INFO_MAX_READ; - - inbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inbox)) { - mlx4_err(dev, - "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(inbox)); - return PTR_ERR(inbox); - } - - outbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outbox)) { - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_err(dev, - "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(outbox)); - return PTR_ERR(outbox); - } - - inmad = (struct mlx4_mad_ifc *)(inbox->buf); - outmad = (struct mlx4_mad_ifc *)(outbox->buf); - - inmad->method = 0x1; /* Get */ - inmad->class_version = 0x1; - inmad->mgmt_class = 0x1; - inmad->base_version = 0x1; - inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ - - if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) - /* Cross pages reads are not allowed - * read until offset 256 in low page - */ - size -= offset + size - I2C_PAGE_SIZE; - - i2c_addr = I2C_ADDR_LOW; - if (offset >= I2C_PAGE_SIZE) { - /* Reset offset to high page */ - i2c_addr = I2C_ADDR_HIGH; - offset -= I2C_PAGE_SIZE; - } - - cable_info = (struct mlx4_cable_info *)inmad->data; - cable_info->dev_mem_address = cpu_to_be16(offset); - cable_info->page_num = 0; - cable_info->i2c_addr = i2c_addr; - cable_info->size = cpu_to_be16(size); - - ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (ret) - goto out; - - if (be16_to_cpu(outmad->status)) { - /* Mad returned with bad status */ - ret = be16_to_cpu(outmad->status); -#ifdef DEBUG - mlx4_warn(dev, "MLX4_CMD_MAD_IFC Get Module info attr(%x) " - "port(%d) i2c_addr(%x) offset(%d) size(%d): Response " - "Mad Status(%x) - %s\n", 0xFF60, port, i2c_addr, offset, - size, ret, cable_info_mad_err_str(ret)); -#endif - if (i2c_addr == I2C_ADDR_HIGH && - MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) - /* Some SFP cables do not support i2c slave - * address 0x51 (high page), abort silently. - */ - ret = 0; - else - ret = -ret; - goto out; - } - cable_info = (struct mlx4_cable_info *)outmad->data; - memcpy(data, cable_info->data, size); - ret = size; -out: - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_free_cmd_mailbox(dev, outbox); - return ret; -} -EXPORT_SYMBOL(mlx4_get_module_info); diff --git a/sys/ofed/drivers/net/mlx4/profile.c b/sys/ofed/drivers/net/mlx4/profile.c deleted file mode 100644 index aa5f957feccd..000000000000 --- a/sys/ofed/drivers/net/mlx4/profile.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/slab.h> - -#include "mlx4.h" -#include "fw.h" - -enum { - MLX4_RES_QP, - MLX4_RES_RDMARC, - MLX4_RES_ALTC, - MLX4_RES_AUXC, - MLX4_RES_SRQ, - MLX4_RES_CQ, - MLX4_RES_EQ, - MLX4_RES_DMPT, - MLX4_RES_CMPT, - MLX4_RES_MTT, - MLX4_RES_MCG, - MLX4_RES_NUM -}; - -static const char *res_name[] = { - [MLX4_RES_QP] = "QP", - [MLX4_RES_RDMARC] = "RDMARC", - [MLX4_RES_ALTC] = "ALTC", - [MLX4_RES_AUXC] = "AUXC", - [MLX4_RES_SRQ] = "SRQ", - [MLX4_RES_CQ] = "CQ", - [MLX4_RES_EQ] = "EQ", - [MLX4_RES_DMPT] = "DMPT", - [MLX4_RES_CMPT] = "CMPT", - [MLX4_RES_MTT] = "MTT", - [MLX4_RES_MCG] = "MCG", -}; - -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) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource { - u64 size; - u64 start; - int type; - u64 num; - int log_num; - }; - - u64 total_size = 0; - struct mlx4_resource *profile; - struct mlx4_resource tmp; - int i, j; - - profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL); - if (!profile) - return -ENOMEM; - - profile[MLX4_RES_QP].size = dev_cap->qpc_entry_sz; - profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz; - profile[MLX4_RES_ALTC].size = dev_cap->altc_entry_sz; - profile[MLX4_RES_AUXC].size = dev_cap->aux_entry_sz; - profile[MLX4_RES_SRQ].size = dev_cap->srq_entry_sz; - profile[MLX4_RES_CQ].size = dev_cap->cqc_entry_sz; - profile[MLX4_RES_EQ].size = dev_cap->eqc_entry_sz; - profile[MLX4_RES_DMPT].size = dev_cap->dmpt_entry_sz; - profile[MLX4_RES_CMPT].size = dev_cap->cmpt_entry_sz; - profile[MLX4_RES_MTT].size = dev_cap->mtt_entry_sz; - profile[MLX4_RES_MCG].size = mlx4_get_mgm_entry_size(dev); - - profile[MLX4_RES_QP].num = request->num_qp; - profile[MLX4_RES_RDMARC].num = request->num_qp * request->rdmarc_per_qp; - profile[MLX4_RES_ALTC].num = request->num_qp; - profile[MLX4_RES_AUXC].num = request->num_qp; - profile[MLX4_RES_SRQ].num = request->num_srq; - profile[MLX4_RES_CQ].num = request->num_cq; - profile[MLX4_RES_EQ].num = mlx4_is_mfunc(dev) ? - dev->phys_caps.num_phys_eqs : - min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); - profile[MLX4_RES_DMPT].num = request->num_mpt; - profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; - profile[MLX4_RES_MTT].num = ((u64)request->num_mtt_segs) * - (1 << log_mtts_per_seg); - profile[MLX4_RES_MCG].num = request->num_mcg; - - for (i = 0; i < MLX4_RES_NUM; ++i) { - profile[i].type = i; - profile[i].num = roundup_pow_of_two(profile[i].num); - profile[i].log_num = ilog2(profile[i].num); - profile[i].size *= profile[i].num; - profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); - } - - /* - * Sort the resources in decreasing order of size. Since they - * all have sizes that are powers of 2, we'll be able to keep - * resources aligned to their size and pack them without gaps - * using the sorted order. - */ - for (i = MLX4_RES_NUM; i > 0; --i) - for (j = 1; j < i; ++j) { - if (profile[j].size > profile[j - 1].size) { - tmp = profile[j]; - profile[j] = profile[j - 1]; - profile[j - 1] = tmp; - } - } - - for (i = 0; i < MLX4_RES_NUM; ++i) { - if (profile[i].size) { - profile[i].start = total_size; - total_size += profile[i].size; - } - - if (total_size > dev_cap->max_icm_sz) { - mlx4_err(dev, "Profile requires 0x%llx bytes; " - "won't fit in 0x%llx bytes of context memory.\n", - (unsigned long long) total_size, - (unsigned long long) dev_cap->max_icm_sz); - kfree(profile); - return -ENOMEM; - } - - if (profile[i].size) - mlx4_dbg(dev, " profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, " - "size 0x%10llx\n", - i, res_name[profile[i].type], profile[i].log_num, - (unsigned long long) profile[i].start, - (unsigned long long) profile[i].size); - } - - mlx4_dbg(dev, "HCA context memory: reserving %d KB\n", - (int) (total_size >> 10)); - - for (i = 0; i < MLX4_RES_NUM; ++i) { - switch (profile[i].type) { - case MLX4_RES_QP: - dev->caps.num_qps = profile[i].num; - init_hca->qpc_base = profile[i].start; - init_hca->log_num_qps = profile[i].log_num; - break; - case MLX4_RES_RDMARC: - for (priv->qp_table.rdmarc_shift = 0; - request->num_qp << priv->qp_table.rdmarc_shift < profile[i].num; - ++priv->qp_table.rdmarc_shift) - ; /* nothing */ - dev->caps.max_qp_dest_rdma = 1 << priv->qp_table.rdmarc_shift; - priv->qp_table.rdmarc_base = (u32) profile[i].start; - init_hca->rdmarc_base = profile[i].start; - init_hca->log_rd_per_qp = priv->qp_table.rdmarc_shift; - break; - case MLX4_RES_ALTC: - init_hca->altc_base = profile[i].start; - break; - case MLX4_RES_AUXC: - init_hca->auxc_base = profile[i].start; - break; - case MLX4_RES_SRQ: - dev->caps.num_srqs = profile[i].num; - init_hca->srqc_base = profile[i].start; - init_hca->log_num_srqs = profile[i].log_num; - break; - case MLX4_RES_CQ: - dev->caps.num_cqs = profile[i].num; - init_hca->cqc_base = profile[i].start; - init_hca->log_num_cqs = profile[i].log_num; - break; - case MLX4_RES_EQ: - dev->caps.num_eqs = roundup_pow_of_two(min_t(unsigned, dev_cap->max_eqs, - MAX_MSIX)); - init_hca->eqc_base = profile[i].start; - init_hca->log_num_eqs = ilog2(dev->caps.num_eqs); - break; - case MLX4_RES_DMPT: - dev->caps.num_mpts = profile[i].num; - priv->mr_table.mpt_base = profile[i].start; - init_hca->dmpt_base = profile[i].start; - init_hca->log_mpt_sz = profile[i].log_num; - break; - case MLX4_RES_CMPT: - init_hca->cmpt_base = profile[i].start; - break; - case MLX4_RES_MTT: - dev->caps.num_mtts = profile[i].num; - priv->mr_table.mtt_base = profile[i].start; - init_hca->mtt_base = profile[i].start; - break; - case MLX4_RES_MCG: - init_hca->mc_base = profile[i].start; - init_hca->log_mc_entry_sz = - ilog2(mlx4_get_mgm_entry_size(dev)); - init_hca->log_mc_table_sz = profile[i].log_num; - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - dev->caps.num_mgms = profile[i].num; - } else { - init_hca->log_mc_hash_sz = - profile[i].log_num - 1; - dev->caps.num_mgms = profile[i].num >> 1; - dev->caps.num_amgms = profile[i].num >> 1; - } - break; - default: - break; - } - } - - /* - * PDs don't take any HCA memory, but we assign them as part - * of the HCA profile anyway. - */ - dev->caps.num_pds = MLX4_NUM_PDS; - - kfree(profile); - return total_size; -} diff --git a/sys/ofed/drivers/net/mlx4/qp.c b/sys/ofed/drivers/net/mlx4/qp.c deleted file mode 100644 index fe8d3c2de07f..000000000000 --- a/sys/ofed/drivers/net/mlx4/qp.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/types.h> -#include <linux/gfp.h> -#include <linux/module.h> - -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/qp.h> - -#include "mlx4.h" -#include "icm.h" - -/* - * QP to support BF should have bits 6,7 cleared - */ -#define MLX4_BF_QP_SKIP_MASK 0xc0 -#define MLX4_MAX_BF_QP_RANGE 0x40 - -void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - struct mlx4_qp *qp; - - spin_lock(&qp_table->lock); - - qp = __mlx4_qp_lookup(dev, qpn); - if (qp) - atomic_inc(&qp->refcount); - - spin_unlock(&qp_table->lock); - - if (!qp) { - mlx4_dbg(dev, "Async event for none existent QP %08x\n", qpn); - return; - } - - qp->event(qp, event_type); - - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); -} - -/* used for INIT/CLOSE port logic */ -static int is_master_qp0(struct mlx4_dev *dev, struct mlx4_qp *qp, int *real_qp0, int *proxy_qp0) -{ - /* this procedure is called after we already know we are on the master */ - /* qp0 is either the proxy qp0, or the real qp0 */ - u32 pf_proxy_offset = dev->phys_caps.base_proxy_sqpn + 8 * mlx4_master_func_num(dev); - *proxy_qp0 = qp->qpn >= pf_proxy_offset && qp->qpn <= pf_proxy_offset + 1; - - *real_qp0 = qp->qpn >= dev->phys_caps.base_sqpn && - qp->qpn <= dev->phys_caps.base_sqpn + 1; - - return *real_qp0 || *proxy_qp0; -} - -static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, - struct mlx4_qp_context *context, - enum mlx4_qp_optpar optpar, - int sqd_event, struct mlx4_qp *qp, int native) -{ - static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = { - [MLX4_QP_STATE_RST] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP, - }, - [MLX4_QP_STATE_INIT] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP, - [MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP, - }, - [MLX4_QP_STATE_RTR] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP, - }, - [MLX4_QP_STATE_RTS] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP, - [MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP, - }, - [MLX4_QP_STATE_SQD] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP, - [MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP, - }, - [MLX4_QP_STATE_SQER] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP, - }, - [MLX4_QP_STATE_ERR] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - } - }; - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - int ret = 0; - int real_qp0 = 0; - int proxy_qp0 = 0; - u8 port; - - if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || - !op[cur_state][new_state]) - return -EINVAL; - - if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) { - ret = mlx4_cmd(dev, 0, qp->qpn, 2, - MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A, native); - if (mlx4_is_master(dev) && cur_state != MLX4_QP_STATE_ERR && - cur_state != MLX4_QP_STATE_RST && - is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { - port = (qp->qpn & 1) + 1; - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; - else - priv->mfunc.master.qp0_state[port].qp0_active = 0; - } - return ret; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { - u64 mtt_addr = mlx4_mtt_addr(dev, mtt); - context->mtt_base_addr_h = mtt_addr >> 32; - context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - } - - *(__be32 *) mailbox->buf = cpu_to_be32(optpar); - memcpy(mailbox->buf + 8, context, sizeof *context); - - ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = - cpu_to_be32(qp->qpn); - - ret = mlx4_cmd(dev, mailbox->dma, - qp->qpn | (!!sqd_event << 31), - new_state == MLX4_QP_STATE_RST ? 2 : 0, - op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C, native); - - if (mlx4_is_master(dev) && is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { - port = (qp->qpn & 1) + 1; - if (cur_state != MLX4_QP_STATE_ERR && - cur_state != MLX4_QP_STATE_RST && - new_state == MLX4_QP_STATE_ERR) { - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; - else - priv->mfunc.master.qp0_state[port].qp0_active = 0; - } else if (new_state == MLX4_QP_STATE_RTR) { - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 1; - else - priv->mfunc.master.qp0_state[port].qp0_active = 1; - } - } - - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} - -int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, - struct mlx4_qp_context *context, - enum mlx4_qp_optpar optpar, - int sqd_event, struct mlx4_qp *qp) -{ - return __mlx4_qp_modify(dev, mtt, cur_state, new_state, context, - optpar, sqd_event, qp, 0); -} -EXPORT_SYMBOL_GPL(mlx4_qp_modify); - -int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags) -{ - int bf_qp = !!(flags & (u8) MLX4_RESERVE_BF_QP); - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - /* Only IPoIB uses a large cnt. In this case, just allocate - * as usual, ignoring bf skipping, since IPoIB does not run over RoCE - */ - if (cnt > MLX4_MAX_BF_QP_RANGE && bf_qp) - bf_qp = 0; - - *base = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align, - bf_qp ? MLX4_BF_QP_SKIP_MASK : 0); - if (*base == -1) - return -ENOMEM; - - return 0; -} - -int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags) -{ - u64 in_param = 0; - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, (((u32) flags) << 24) | (u32) cnt); - set_param_h(&in_param, align); - err = mlx4_cmd_imm(dev, in_param, &out_param, - RES_QP, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - - *base = get_param_l(&out_param); - return 0; - } - return __mlx4_qp_reserve_range(dev, cnt, align, base, flags); -} -EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); - -void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - if (mlx4_is_qp_reserved(dev, (u32) base_qpn)) - return; - mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, MLX4_USE_RR); -} - -void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, base_qpn); - set_param_h(&in_param, cnt); - err = mlx4_cmd(dev, in_param, RES_QP, RES_OP_RESERVE, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) { - mlx4_warn(dev, "Failed to release qp range" - " base:%d cnt:%d\n", base_qpn, cnt); - } - } else - __mlx4_qp_release_range(dev, base_qpn, cnt); -} -EXPORT_SYMBOL_GPL(mlx4_qp_release_range); - -int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - int err; - - err = mlx4_table_get(dev, &qp_table->qp_table, qpn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &qp_table->auxc_table, qpn); - if (err) - goto err_put_qp; - - err = mlx4_table_get(dev, &qp_table->altc_table, qpn); - if (err) - goto err_put_auxc; - - err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn); - if (err) - goto err_put_altc; - - err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn); - if (err) - goto err_put_rdmarc; - - return 0; - -err_put_rdmarc: - mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); - -err_put_altc: - mlx4_table_put(dev, &qp_table->altc_table, qpn); - -err_put_auxc: - mlx4_table_put(dev, &qp_table->auxc_table, qpn); - -err_put_qp: - mlx4_table_put(dev, &qp_table->qp_table, qpn); - -err_out: - return err; -} - -static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) -{ - u64 param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(¶m, qpn); - return mlx4_cmd_imm(dev, param, ¶m, RES_QP, RES_OP_MAP_ICM, - MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - } - return __mlx4_qp_alloc_icm(dev, qpn); -} - -void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - mlx4_table_put(dev, &qp_table->cmpt_table, qpn); - mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); - mlx4_table_put(dev, &qp_table->altc_table, qpn); - mlx4_table_put(dev, &qp_table->auxc_table, qpn); - mlx4_table_put(dev, &qp_table->qp_table, qpn); -} - -static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, qpn); - if (mlx4_cmd(dev, in_param, RES_QP, RES_OP_MAP_ICM, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to free icm of qp:%d\n", qpn); - } else - __mlx4_qp_free_icm(dev, qpn); -} - -int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - int err; - - if (!qpn) - return -EINVAL; - - qp->qpn = qpn; - - err = mlx4_qp_alloc_icm(dev, qpn); - if (err) - return err; - - spin_lock_irq(&qp_table->lock); - err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & - (dev->caps.num_qps - 1), qp); - spin_unlock_irq(&qp_table->lock); - if (err) - goto err_icm; - - atomic_set(&qp->refcount, 1); - init_completion(&qp->free); - - return 0; - -err_icm: - mlx4_qp_free_icm(dev, qpn); - return err; -} - -EXPORT_SYMBOL_GPL(mlx4_qp_alloc); - -void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - unsigned long flags; - - spin_lock_irqsave(&qp_table->lock, flags); - radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); - spin_unlock_irqrestore(&qp_table->lock, flags); -} -EXPORT_SYMBOL_GPL(mlx4_qp_remove); - -void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) -{ - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); - wait_for_completion(&qp->free); - - mlx4_qp_free_icm(dev, qp->qpn); -} -EXPORT_SYMBOL_GPL(mlx4_qp_free); - -static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) -{ - return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_init_qp_table(struct mlx4_dev *dev) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - int err; - int reserved_from_top = 0; - int reserved_from_bot; - int k; - - spin_lock_init(&qp_table->lock); - INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - /* - * We reserve 2 extra QPs per port for the special QPs. The - * block of special QPs must be aligned to a multiple of 8, so - * round up. - * - * We also reserve the MSB of the 24-bit QP number to indicate - * that a QP is an XRC QP. - */ - dev->phys_caps.base_sqpn = - ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8); - - { - int sort[MLX4_NUM_QP_REGION]; - int i, j, tmp; - int last_base = dev->caps.num_qps; - - for (i = 1; i < MLX4_NUM_QP_REGION; ++i) - sort[i] = i; - - for (i = MLX4_NUM_QP_REGION; i > 0; --i) { - for (j = 2; j < i; ++j) { - if (dev->caps.reserved_qps_cnt[sort[j]] > - dev->caps.reserved_qps_cnt[sort[j - 1]]) { - tmp = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = tmp; - } - } - } - - for (i = 1; i < MLX4_NUM_QP_REGION; ++i) { - last_base -= dev->caps.reserved_qps_cnt[sort[i]]; - dev->caps.reserved_qps_base[sort[i]] = last_base; - reserved_from_top += - dev->caps.reserved_qps_cnt[sort[i]]; - } - - } - - /* Reserve 8 real SQPs in both native and SRIOV modes. - * In addition, in SRIOV mode, reserve 8 proxy SQPs per function - * (for all PFs and VFs), and 8 corresponding tunnel QPs. - * Each proxy SQP works opposite its own tunnel QP. - * - * The QPs are arranged as follows: - * a. 8 real SQPs - * b. All the proxy SQPs (8 per function) - * c. All the tunnel QPs (8 per function) - */ - reserved_from_bot = mlx4_num_reserved_sqps(dev); - if (reserved_from_bot + reserved_from_top > dev->caps.num_qps) { - mlx4_err(dev, "Number of reserved QPs is higher than number " - "of QPs, increase the value of log_num_qp\n"); - return -EINVAL; - } - - err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps, - (1 << 23) - 1, reserved_from_bot, - reserved_from_top); - if (err) - return err; - - if (mlx4_is_mfunc(dev)) { - /* for PPF use */ - dev->phys_caps.base_proxy_sqpn = dev->phys_caps.base_sqpn + 8; - dev->phys_caps.base_tunnel_sqpn = dev->phys_caps.base_sqpn + 8 + 8 * MLX4_MFUNC_MAX; - - /* In mfunc, calculate proxy and tunnel qp offsets for the PF here, - * since the PF does not call mlx4_slave_caps */ - dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - - if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy || - !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) { - err = -ENOMEM; - goto err_mem; - } - - for (k = 0; k < dev->caps.num_ports; k++) { - dev->caps.qp0_proxy[k] = dev->phys_caps.base_proxy_sqpn + - 8 * mlx4_master_func_num(dev) + k; - dev->caps.qp0_tunnel[k] = dev->caps.qp0_proxy[k] + 8 * MLX4_MFUNC_MAX; - dev->caps.qp1_proxy[k] = dev->phys_caps.base_proxy_sqpn + - 8 * mlx4_master_func_num(dev) + MLX4_MAX_PORTS + k; - dev->caps.qp1_tunnel[k] = dev->caps.qp1_proxy[k] + 8 * MLX4_MFUNC_MAX; - } - } - - - err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn); - if (err) - goto err_mem; - return 0; - -err_mem: - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - dev->caps.qp0_tunnel = dev->caps.qp0_proxy = - dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL; - return err; -} - -void mlx4_cleanup_qp_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - - mlx4_CONF_SPECIAL_QP(dev, 0); - mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap); -} - -int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, - struct mlx4_qp_context *context) -{ - struct mlx4_cmd_mailbox *mailbox; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0, - MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (!err) - memcpy(context, mailbox->buf + 8, sizeof *context); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_qp_query); - -int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_qp_context *context, - struct mlx4_qp *qp, enum mlx4_qp_state *qp_state) -{ - int err; - int i; - enum mlx4_qp_state states[] = { - MLX4_QP_STATE_RST, - MLX4_QP_STATE_INIT, - MLX4_QP_STATE_RTR, - MLX4_QP_STATE_RTS - }; - - for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { - context->flags &= cpu_to_be32(~(0xf << 28)); - context->flags |= cpu_to_be32(states[i + 1] << 28); - err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], - context, 0, 0, qp); - if (err) { - mlx4_err(dev, "Failed to bring QP to state: " - "%d with error: %d\n", - states[i + 1], err); - return err; - } - - *qp_state = states[i + 1]; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_qp_to_ready); diff --git a/sys/ofed/drivers/net/mlx4/reset.c b/sys/ofed/drivers/net/mlx4/reset.c deleted file mode 100644 index 44ec1e12b898..000000000000 --- a/sys/ofed/drivers/net/mlx4/reset.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/errno.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/jiffies.h> - -#include "mlx4.h" - -int mlx4_reset(struct mlx4_dev *dev) -{ - void __iomem *reset; - u32 *hca_header = NULL; - int pcie_cap; - u16 devctl; - u16 linkctl; - u16 vendor; - unsigned long end; - u32 sem; - int i; - int err = 0; - -#define MLX4_RESET_BASE 0xf0000 -#define MLX4_RESET_SIZE 0x400 -#define MLX4_SEM_OFFSET 0x3fc -#define MLX4_RESET_OFFSET 0x10 -#define MLX4_RESET_VALUE swab32(1) - -#define MLX4_SEM_TIMEOUT_JIFFIES (10 * HZ) -#define MLX4_RESET_TIMEOUT_JIFFIES (2 * HZ) - - /* - * Reset the chip. This is somewhat ugly because we have to - * save off the PCI header before reset and then restore it - * after the chip reboots. We skip config space offsets 22 - * and 23 since those have a special meaning. - */ - - /* Do we need to save off the full 4K PCI Express header?? */ - hca_header = kmalloc(256, GFP_KERNEL); - if (!hca_header) { - err = -ENOMEM; - mlx4_err(dev, "Couldn't allocate memory to save HCA " - "PCI header, aborting.\n"); - goto out; - } - - pcie_cap = pci_pcie_cap(dev->pdev); - - for (i = 0; i < 64; ++i) { - if (i == 22 || i == 23) - continue; - if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't save HCA " - "PCI header, aborting.\n"); - goto out; - } - } - - reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, - MLX4_RESET_SIZE); - if (!reset) { - err = -ENOMEM; - mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n"); - goto out; - } - - /* grab HW semaphore to lock out flash updates */ - end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES; - do { - sem = readl(reset + MLX4_SEM_OFFSET); - if (!sem) - break; - - msleep(1); - } while (time_before(jiffies, end)); - - if (sem) { - mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n"); - err = -EAGAIN; - iounmap(reset); - goto out; - } - - /* actually hit reset */ - writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET); - iounmap(reset); - - /* wait half a second before accessing device */ - msleep(500); - - end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; - do { - if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && - vendor != 0xffff) - break; - - msleep(1); - } while (time_before(jiffies, end)); - - if (vendor == 0xffff) { - err = -ENODEV; - mlx4_err(dev, "PCI device did not come back after reset, " - "aborting.\n"); - goto out; - } - - /* Now restore the PCI headers */ - if (pcie_cap) { - devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL, - devctl)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA PCI Express " - "Device Control register, aborting.\n"); - goto out; - } - linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL, - linkctl)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA PCI Express " - "Link control register, aborting.\n"); - goto out; - } - } - - for (i = 0; i < 16; ++i) { - if (i * 4 == PCI_COMMAND) - continue; - - if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA reg %x, " - "aborting.\n", i); - goto out; - } - } - - if (pci_write_config_dword(dev->pdev, PCI_COMMAND, - hca_header[PCI_COMMAND / 4])) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA COMMAND, " - "aborting.\n"); - goto out; - } - -out: - kfree(hca_header); - - return err; -} diff --git a/sys/ofed/drivers/net/mlx4/resource_tracker.c b/sys/ofed/drivers/net/mlx4/resource_tracker.c deleted file mode 100644 index 1bdab675ad1e..000000000000 --- a/sys/ofed/drivers/net/mlx4/resource_tracker.c +++ /dev/null @@ -1,4686 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. - * All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/sched.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/qp.h> -#include <linux/if_ether.h> -#include <linux/etherdevice.h> - -#include "mlx4.h" -#include "fw.h" - -#define MLX4_MAC_VALID (1ull << 63) - -struct mac_res { - struct list_head list; - u64 mac; - int ref_count; - u8 smac_index; - u8 port; -}; - -struct vlan_res { - struct list_head list; - u16 vlan; - int ref_count; - int vlan_index; - u8 port; -}; - -struct res_common { - struct list_head list; - struct rb_node node; - u64 res_id; - int owner; - int state; - int from_state; - int to_state; - int removing; -}; - -enum { - RES_ANY_BUSY = 1 -}; - -struct res_gid { - struct list_head list; - u8 gid[16]; - enum mlx4_protocol prot; - enum mlx4_steer_type steer; - u64 reg_id; -}; - -enum res_qp_states { - RES_QP_BUSY = RES_ANY_BUSY, - - /* QP number was allocated */ - RES_QP_RESERVED, - - /* ICM memory for QP context was mapped */ - RES_QP_MAPPED, - - /* QP is in hw ownership */ - RES_QP_HW -}; - -struct res_qp { - struct res_common com; - struct res_mtt *mtt; - struct res_cq *rcq; - struct res_cq *scq; - struct res_srq *srq; - struct list_head mcg_list; - spinlock_t mcg_spl; - int local_qpn; - atomic_t ref_count; - u32 qpc_flags; - /* saved qp params before VST enforcement in order to restore on VGT */ - u8 sched_queue; - __be32 param3; - u8 vlan_control; - u8 fvl_rx; - u8 pri_path_fl; - u8 vlan_index; - u8 feup; -}; - -enum res_mtt_states { - RES_MTT_BUSY = RES_ANY_BUSY, - RES_MTT_ALLOCATED, -}; - -static inline const char *mtt_states_str(enum res_mtt_states state) -{ - switch (state) { - case RES_MTT_BUSY: return "RES_MTT_BUSY"; - case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; - default: return "Unknown"; - } -} - -struct res_mtt { - struct res_common com; - int order; - atomic_t ref_count; -}; - -enum res_mpt_states { - RES_MPT_BUSY = RES_ANY_BUSY, - RES_MPT_RESERVED, - RES_MPT_MAPPED, - RES_MPT_HW, -}; - -struct res_mpt { - struct res_common com; - struct res_mtt *mtt; - int key; -}; - -enum res_eq_states { - RES_EQ_BUSY = RES_ANY_BUSY, - RES_EQ_RESERVED, - RES_EQ_HW, -}; - -struct res_eq { - struct res_common com; - struct res_mtt *mtt; -}; - -enum res_cq_states { - RES_CQ_BUSY = RES_ANY_BUSY, - RES_CQ_ALLOCATED, - RES_CQ_HW, -}; - -struct res_cq { - struct res_common com; - struct res_mtt *mtt; - atomic_t ref_count; -}; - -enum res_srq_states { - RES_SRQ_BUSY = RES_ANY_BUSY, - RES_SRQ_ALLOCATED, - RES_SRQ_HW, -}; - -struct res_srq { - struct res_common com; - struct res_mtt *mtt; - struct res_cq *cq; - atomic_t ref_count; -}; - -enum res_counter_states { - RES_COUNTER_BUSY = RES_ANY_BUSY, - RES_COUNTER_ALLOCATED, -}; - -struct res_counter { - struct res_common com; - int port; -}; - -enum res_xrcdn_states { - RES_XRCD_BUSY = RES_ANY_BUSY, - RES_XRCD_ALLOCATED, -}; - -struct res_xrcdn { - struct res_common com; - int port; -}; - -enum res_fs_rule_states { - RES_FS_RULE_BUSY = RES_ANY_BUSY, - RES_FS_RULE_ALLOCATED, -}; - -struct res_fs_rule { - struct res_common com; - int qpn; -}; - -static int mlx4_is_eth(struct mlx4_dev *dev, int port) -{ - return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; -} - -static void *res_tracker_lookup(struct rb_root *root, u64 res_id) -{ - struct rb_node *node = root->rb_node; - - while (node) { - struct res_common *res = container_of(node, struct res_common, - node); - - if (res_id < res->res_id) - node = node->rb_left; - else if (res_id > res->res_id) - node = node->rb_right; - else - return res; - } - return NULL; -} - -static int res_tracker_insert(struct rb_root *root, struct res_common *res) -{ - struct rb_node **new = &(root->rb_node), *parent = NULL; - - /* Figure out where to put new node */ - while (*new) { - struct res_common *this = container_of(*new, struct res_common, - node); - - parent = *new; - if (res->res_id < this->res_id) - new = &((*new)->rb_left); - else if (res->res_id > this->res_id) - new = &((*new)->rb_right); - else - return -EEXIST; - } - - /* Add new node and rebalance tree. */ - rb_link_node(&res->node, parent, new); - rb_insert_color(&res->node, root); - - return 0; -} - -enum qp_transition { - QP_TRANS_INIT2RTR, - QP_TRANS_RTR2RTS, - QP_TRANS_RTS2RTS, - QP_TRANS_SQERR2RTS, - QP_TRANS_SQD2SQD, - QP_TRANS_SQD2RTS -}; - -/* For Debug uses */ -static const char *ResourceType(enum mlx4_resource rt) -{ - switch (rt) { - case RES_QP: return "RES_QP"; - case RES_CQ: return "RES_CQ"; - case RES_SRQ: return "RES_SRQ"; - case RES_MPT: return "RES_MPT"; - case RES_MTT: return "RES_MTT"; - case RES_MAC: return "RES_MAC"; - case RES_VLAN: return "RES_VLAN"; - case RES_EQ: return "RES_EQ"; - case RES_COUNTER: return "RES_COUNTER"; - case RES_FS_RULE: return "RES_FS_RULE"; - case RES_XRCD: return "RES_XRCD"; - default: return "Unknown resource type !!!"; - }; -} - -static void rem_slave_vlans(struct mlx4_dev *dev, int slave); -static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, - enum mlx4_resource res_type, int count, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[res_type]; - int err = -EINVAL; - int allocated, free, reserved, guaranteed, from_free; - - spin_lock(&res_alloc->alloc_lock); - allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : - res_alloc->allocated[slave]; - free = (port > 0) ? res_alloc->res_port_free[port - 1] : - res_alloc->res_free; - reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : - res_alloc->res_reserved; - guaranteed = res_alloc->guaranteed[slave]; - - if (allocated + count > res_alloc->quota[slave]) - goto out; - - if (allocated + count <= guaranteed) { - err = 0; - } else { - /* portion may need to be obtained from free area */ - if (guaranteed - allocated > 0) - from_free = count - (guaranteed - allocated); - else - from_free = count; - - if (free - from_free > reserved) - err = 0; - } - - if (!err) { - /* grant the request */ - if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; - res_alloc->res_port_free[port - 1] -= count; - } else { - res_alloc->allocated[slave] += count; - res_alloc->res_free -= count; - } - } - -out: - spin_unlock(&res_alloc->alloc_lock); - return err; - -} - -static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, - enum mlx4_resource res_type, int count, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[res_type]; - - spin_lock(&res_alloc->alloc_lock); - if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; - res_alloc->res_port_free[port - 1] += count; - } else { - res_alloc->allocated[slave] -= count; - res_alloc->res_free += count; - } - - spin_unlock(&res_alloc->alloc_lock); - return; -} - -static inline void initialize_res_quotas(struct mlx4_dev *dev, - struct resource_allocator *res_alloc, - enum mlx4_resource res_type, - int vf, int num_instances) -{ - res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); - res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; - if (vf == mlx4_master_func_num(dev)) { - res_alloc->res_free = num_instances; - if (res_type == RES_MTT) { - /* reserved mtts will be taken out of the PF allocation */ - res_alloc->res_free += dev->caps.reserved_mtts; - res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; - res_alloc->quota[vf] += dev->caps.reserved_mtts; - } - } -} - -void mlx4_init_quotas(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int pf; - - /* quotas for VFs are initialized in mlx4_slave_cap */ - if (mlx4_is_slave(dev)) - return; - - if (!mlx4_is_mfunc(dev)) { - dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - - mlx4_num_reserved_sqps(dev); - dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; - dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; - dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; - dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; - return; - } - - pf = mlx4_master_func_num(dev); - dev->quotas.qp = - priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; - dev->quotas.cq = - priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; - dev->quotas.srq = - priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; - dev->quotas.mtt = - priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; - dev->quotas.mpt = - priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; -} -int mlx4_init_resource_tracker(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, j; - int t; - - priv->mfunc.master.res_tracker.slave_list = - kzalloc(dev->num_slaves * sizeof(struct slave_list), - GFP_KERNEL); - if (!priv->mfunc.master.res_tracker.slave_list) - return -ENOMEM; - - for (i = 0 ; i < dev->num_slaves; i++) { - for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) - INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. - slave_list[i].res_list[t]); - mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - } - - mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", - dev->num_slaves); - for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) - priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; - - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[i]; - res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - if (i == RES_MAC || i == RES_VLAN) - res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * - (dev->num_vfs + 1) * sizeof(int), - GFP_KERNEL); - else - res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - - if (!res_alloc->quota || !res_alloc->guaranteed || - !res_alloc->allocated) - goto no_mem_err; - - spin_lock_init(&res_alloc->alloc_lock); - for (t = 0; t < dev->num_vfs + 1; t++) { - switch (i) { - case RES_QP: - initialize_res_quotas(dev, res_alloc, RES_QP, - t, dev->caps.num_qps - - dev->caps.reserved_qps - - mlx4_num_reserved_sqps(dev)); - break; - case RES_CQ: - initialize_res_quotas(dev, res_alloc, RES_CQ, - t, dev->caps.num_cqs - - dev->caps.reserved_cqs); - break; - case RES_SRQ: - initialize_res_quotas(dev, res_alloc, RES_SRQ, - t, dev->caps.num_srqs - - dev->caps.reserved_srqs); - break; - case RES_MPT: - initialize_res_quotas(dev, res_alloc, RES_MPT, - t, dev->caps.num_mpts - - dev->caps.reserved_mrws); - break; - case RES_MTT: - initialize_res_quotas(dev, res_alloc, RES_MTT, - t, dev->caps.num_mtts - - dev->caps.reserved_mtts); - break; - case RES_MAC: - if (t == mlx4_master_func_num(dev)) { - res_alloc->quota[t] = - MLX4_MAX_MAC_NUM - 2 * dev->num_vfs; - res_alloc->guaranteed[t] = res_alloc->quota[t]; - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM; - } else { - res_alloc->quota[t] = 2; - res_alloc->guaranteed[t] = 2; - } - break; - case RES_VLAN: - if (t == mlx4_master_func_num(dev)) { - res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; - res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_free[j] = - res_alloc->quota[t]; - } else { - res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; - res_alloc->guaranteed[t] = 0; - } - break; - case RES_COUNTER: - res_alloc->quota[t] = dev->caps.max_counters; - res_alloc->guaranteed[t] = 0; - if (t == mlx4_master_func_num(dev)) - res_alloc->res_free = res_alloc->quota[t]; - break; - default: - break; - } - if (i == RES_MAC || i == RES_VLAN) { - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_rsvd[j] += - res_alloc->guaranteed[t]; - } else { - res_alloc->res_reserved += res_alloc->guaranteed[t]; - } - } - } - spin_lock_init(&priv->mfunc.master.res_tracker.lock); - return 0; - -no_mem_err: - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); - priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); - priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); - priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; - } - return -ENOMEM; -} - -void mlx4_free_resource_tracker(struct mlx4_dev *dev, - enum mlx4_res_tracker_free_type type) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - if (priv->mfunc.master.res_tracker.slave_list) { - if (type != RES_TR_FREE_STRUCTS_ONLY) { - for (i = 0; i < dev->num_slaves; i++) { - if (type == RES_TR_FREE_ALL || - dev->caps.function != i) - mlx4_delete_all_resources_for_slave(dev, i); - } - /* free master's vlans */ - i = dev->caps.function; - mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - rem_slave_vlans(dev, i); - mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - } - - if (type != RES_TR_FREE_SLAVES_ONLY) { - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); - priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); - priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); - priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; - } - kfree(priv->mfunc.master.res_tracker.slave_list); - priv->mfunc.master.res_tracker.slave_list = NULL; - } - } -} - -static void update_pkey_index(struct mlx4_dev *dev, int slave, - struct mlx4_cmd_mailbox *inbox) -{ - u8 sched = *(u8 *)(inbox->buf + 64); - u8 orig_index = *(u8 *)(inbox->buf + 35); - u8 new_index; - struct mlx4_priv *priv = mlx4_priv(dev); - int port; - - port = (sched >> 6 & 1) + 1; - - new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; - *(u8 *)(inbox->buf + 35) = new_index; -} - -static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, - u8 slave) -{ - struct mlx4_qp_context *qp_ctx = inbox->buf + 8; - enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); - u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; - int port; - - if (MLX4_QP_ST_UD == ts) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) - qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; - else - qp_ctx->pri_path.mgid_index = 0x80 | slave; - - } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) { - qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); - qp_ctx->pri_path.mgid_index &= 0x7f; - } else { - qp_ctx->pri_path.mgid_index = slave & 0x7F; - } - } - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { - port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) { - qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); - qp_ctx->alt_path.mgid_index &= 0x7f; - } else { - qp_ctx->alt_path.mgid_index = slave & 0x7F; - } - } - } -} - -static int check_counter_index_validity(struct mlx4_dev *dev, int slave, int port, int idx) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *counter, *tmp_counter; - - if (slave == 0) { - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.global_port_list[port - 1], - list) { - if (counter->index == idx) - return 0; - } - return -EINVAL; - } else { - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.vf_list[slave - 1][port - 1], - list) { - if (counter->index == idx) - return 0; - } - return -EINVAL; - } -} - -static int update_vport_qp_param(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *inbox, - u8 slave, u32 qpn) -{ - struct mlx4_qp_context *qpc = inbox->buf + 8; - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_priv *priv; - u32 qp_type; - int port; - - port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; - priv = mlx4_priv(dev); - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && - qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX) { - if (check_counter_index_validity(dev, slave, port, - qpc->pri_path.counter_index)) - return -EINVAL; - } - - mlx4_dbg(dev, "%s: QP counter_index %d for slave %d port %d\n", - __func__, qpc->pri_path.counter_index, slave, port); - - if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && - dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && - !mlx4_is_qp_reserved(dev, qpn) && - qp_type == MLX4_QP_ST_MLX && - qpc->pri_path.counter_index != 0xFF) { - /* disable multicast loopback to qp with same counter */ - qpc->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - } - - if (MLX4_VGT != vp_oper->state.default_vlan) { - /* the reserved QPs (special, proxy, tunnel) - * do not operate over vlans - */ - if (mlx4_is_qp_reserved(dev, qpn)) - return 0; - - /* force strip vlan by clear vsd */ - qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); - /* preserve IF_COUNTER flag */ - qpc->pri_path.vlan_control &= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - if (MLX4_QP_ST_RC != qp_type) { - if (0 != vp_oper->state.default_vlan) { - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; - } else { /* priority tagged */ - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; - } - } - qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; - qpc->pri_path.vlan_index = vp_oper->vlan_idx; - qpc->pri_path.fl |= MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; - qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; - qpc->pri_path.sched_queue &= 0xC7; - qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; - } - if (vp_oper->state.spoofchk) { - qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; - qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; - } - return 0; -} - -static int mpt_mask(struct mlx4_dev *dev) -{ - return dev->caps.num_mpts - 1; -} - -static void *find_res(struct mlx4_dev *dev, u64 res_id, - enum mlx4_resource type) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], - res_id); -} - -static int get_res(struct mlx4_dev *dev, int slave, u64 res_id, - enum mlx4_resource type, - void *res) -{ - struct res_common *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = find_res(dev, res_id, type); - if (!r) { - err = -ENONET; - goto exit; - } - - if (r->state == RES_ANY_BUSY) { - err = -EBUSY; - goto exit; - } - - if (r->owner != slave) { - err = -EPERM; - goto exit; - } - - r->from_state = r->state; - r->state = RES_ANY_BUSY; - - if (res) - *((struct res_common **)res) = r; - -exit: - spin_unlock_irq(mlx4_tlock(dev)); - return err; -} - -int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, - enum mlx4_resource type, - u64 res_id, int *slave) -{ - - struct res_common *r; - int err = -ENOENT; - int id = res_id; - - if (type == RES_QP) - id &= 0x7fffff; - spin_lock(mlx4_tlock(dev)); - - r = find_res(dev, id, type); - if (r) { - *slave = r->owner; - err = 0; - } - spin_unlock(mlx4_tlock(dev)); - - return err; -} - -static void put_res(struct mlx4_dev *dev, int slave, u64 res_id, - enum mlx4_resource type) -{ - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = find_res(dev, res_id, type); - if (r) - r->state = r->from_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static struct res_common *alloc_qp_tr(int id) -{ - struct res_qp *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_QP_RESERVED; - ret->local_qpn = id; - INIT_LIST_HEAD(&ret->mcg_list); - spin_lock_init(&ret->mcg_spl); - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_mtt_tr(int id, int order) -{ - struct res_mtt *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->order = order; - ret->com.state = RES_MTT_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_mpt_tr(int id, int key) -{ - struct res_mpt *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_MPT_RESERVED; - ret->key = key; - - return &ret->com; -} - -static struct res_common *alloc_eq_tr(int id) -{ - struct res_eq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_EQ_RESERVED; - - return &ret->com; -} - -static struct res_common *alloc_cq_tr(int id) -{ - struct res_cq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_CQ_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_srq_tr(int id) -{ - struct res_srq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_SRQ_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_counter_tr(int id) -{ - struct res_counter *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_COUNTER_ALLOCATED; - - return &ret->com; -} - -static struct res_common *alloc_xrcdn_tr(int id) -{ - struct res_xrcdn *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_XRCD_ALLOCATED; - - return &ret->com; -} - -static struct res_common *alloc_fs_rule_tr(u64 id, int qpn) -{ - struct res_fs_rule *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_FS_RULE_ALLOCATED; - ret->qpn = qpn; - return &ret->com; -} - -static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, - int extra) -{ - struct res_common *ret; - - switch (type) { - case RES_QP: - ret = alloc_qp_tr(id); - break; - case RES_MPT: - ret = alloc_mpt_tr(id, extra); - break; - case RES_MTT: - ret = alloc_mtt_tr(id, extra); - break; - case RES_EQ: - ret = alloc_eq_tr(id); - break; - case RES_CQ: - ret = alloc_cq_tr(id); - break; - case RES_SRQ: - ret = alloc_srq_tr(id); - break; - case RES_MAC: - printk(KERN_ERR "implementation missing\n"); - return NULL; - case RES_COUNTER: - ret = alloc_counter_tr(id); - break; - case RES_XRCD: - ret = alloc_xrcdn_tr(id); - break; - case RES_FS_RULE: - ret = alloc_fs_rule_tr(id, extra); - break; - default: - return NULL; - } - if (ret) - ret->owner = slave; - - return ret; -} - -static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, - enum mlx4_resource type, int extra) -{ - int i; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct res_common **res_arr; - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct rb_root *root = &tracker->res_tree[type]; - - res_arr = kzalloc(count * sizeof *res_arr, GFP_KERNEL); - if (!res_arr) - return -ENOMEM; - - for (i = 0; i < count; ++i) { - res_arr[i] = alloc_tr(base + i, type, slave, extra); - if (!res_arr[i]) { - for (--i; i >= 0; --i) - kfree(res_arr[i]); - - kfree(res_arr); - return -ENOMEM; - } - } - - spin_lock_irq(mlx4_tlock(dev)); - for (i = 0; i < count; ++i) { - if (find_res(dev, base + i, type)) { - err = -EEXIST; - goto undo; - } - err = res_tracker_insert(root, res_arr[i]); - if (err) - goto undo; - list_add_tail(&res_arr[i]->list, - &tracker->slave_list[slave].res_list[type]); - } - spin_unlock_irq(mlx4_tlock(dev)); - kfree(res_arr); - - return 0; - -undo: - for (--i; i >= 0; --i) { - rb_erase(&res_arr[i]->node, root); - list_del_init(&res_arr[i]->list); - } - - spin_unlock_irq(mlx4_tlock(dev)); - - for (i = 0; i < count; ++i) - kfree(res_arr[i]); - - kfree(res_arr); - - return err; -} - -static int remove_qp_ok(struct res_qp *res) -{ - if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || - !list_empty(&res->mcg_list)) { - pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", - res->com.state, atomic_read(&res->ref_count)); - return -EBUSY; - } else if (res->com.state != RES_QP_RESERVED) { - return -EPERM; - } - - return 0; -} - -static int remove_mtt_ok(struct res_mtt *res, int order) -{ - if (res->com.state == RES_MTT_BUSY || - atomic_read(&res->ref_count)) { - printk(KERN_DEBUG "%s-%d: state %s, ref_count %d\n", - __func__, __LINE__, - mtt_states_str(res->com.state), - atomic_read(&res->ref_count)); - return -EBUSY; - } else if (res->com.state != RES_MTT_ALLOCATED) - return -EPERM; - else if (res->order != order) - return -EINVAL; - - return 0; -} - -static int remove_mpt_ok(struct res_mpt *res) -{ - if (res->com.state == RES_MPT_BUSY) - return -EBUSY; - else if (res->com.state != RES_MPT_RESERVED) - return -EPERM; - - return 0; -} - -static int remove_eq_ok(struct res_eq *res) -{ - if (res->com.state == RES_MPT_BUSY) - return -EBUSY; - else if (res->com.state != RES_MPT_RESERVED) - return -EPERM; - - return 0; -} - -static int remove_counter_ok(struct res_counter *res) -{ - if (res->com.state == RES_COUNTER_BUSY) - return -EBUSY; - else if (res->com.state != RES_COUNTER_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_xrcdn_ok(struct res_xrcdn *res) -{ - if (res->com.state == RES_XRCD_BUSY) - return -EBUSY; - else if (res->com.state != RES_XRCD_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_fs_rule_ok(struct res_fs_rule *res) -{ - if (res->com.state == RES_FS_RULE_BUSY) - return -EBUSY; - else if (res->com.state != RES_FS_RULE_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_cq_ok(struct res_cq *res) -{ - if (res->com.state == RES_CQ_BUSY) - return -EBUSY; - else if (res->com.state != RES_CQ_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_srq_ok(struct res_srq *res) -{ - if (res->com.state == RES_SRQ_BUSY) - return -EBUSY; - else if (res->com.state != RES_SRQ_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) -{ - switch (type) { - case RES_QP: - return remove_qp_ok((struct res_qp *)res); - case RES_CQ: - return remove_cq_ok((struct res_cq *)res); - case RES_SRQ: - return remove_srq_ok((struct res_srq *)res); - case RES_MPT: - return remove_mpt_ok((struct res_mpt *)res); - case RES_MTT: - return remove_mtt_ok((struct res_mtt *)res, extra); - case RES_MAC: - return -ENOSYS; - case RES_EQ: - return remove_eq_ok((struct res_eq *)res); - case RES_COUNTER: - return remove_counter_ok((struct res_counter *)res); - case RES_XRCD: - return remove_xrcdn_ok((struct res_xrcdn *)res); - case RES_FS_RULE: - return remove_fs_rule_ok((struct res_fs_rule *)res); - default: - return -EINVAL; - } -} - -static int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, - enum mlx4_resource type, int extra) -{ - u64 i; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - for (i = base; i < base + count; ++i) { - r = res_tracker_lookup(&tracker->res_tree[type], i); - if (!r) { - err = -ENOENT; - goto out; - } - if (r->owner != slave) { - err = -EPERM; - goto out; - } - err = remove_ok(r, type, extra); - if (err) - goto out; - } - - for (i = base; i < base + count; ++i) { - r = res_tracker_lookup(&tracker->res_tree[type], i); - rb_erase(&r->node, &tracker->res_tree[type]); - list_del(&r->list); - kfree(r); - } - err = 0; - -out: - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, - enum res_qp_states state, struct res_qp **qp, - int alloc) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_qp *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_QP_BUSY: - mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", - __func__, (unsigned long long)r->com.res_id); - err = -EBUSY; - break; - - case RES_QP_RESERVED: - if (r->com.state == RES_QP_MAPPED && !alloc) - break; - - mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", (unsigned long long)r->com.res_id); - err = -EINVAL; - break; - - case RES_QP_MAPPED: - if ((r->com.state == RES_QP_RESERVED && alloc) || - r->com.state == RES_QP_HW) - break; - else { - mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", - (unsigned long long)r->com.res_id); - err = -EINVAL; - } - - break; - - case RES_QP_HW: - if (r->com.state != RES_QP_MAPPED) - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_QP_BUSY; - if (qp) - *qp = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_mpt_states state, struct res_mpt **mpt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_mpt *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_MPT_BUSY: - err = -EINVAL; - break; - - case RES_MPT_RESERVED: - if (r->com.state != RES_MPT_MAPPED) - err = -EINVAL; - break; - - case RES_MPT_MAPPED: - if (r->com.state != RES_MPT_RESERVED && - r->com.state != RES_MPT_HW) - err = -EINVAL; - break; - - case RES_MPT_HW: - if (r->com.state != RES_MPT_MAPPED) - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_MPT_BUSY; - if (mpt) - *mpt = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_eq_states state, struct res_eq **eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_eq *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_EQ_BUSY: - err = -EINVAL; - break; - - case RES_EQ_RESERVED: - if (r->com.state != RES_EQ_HW) - err = -EINVAL; - break; - - case RES_EQ_HW: - if (r->com.state != RES_EQ_RESERVED) - err = -EINVAL; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_EQ_BUSY; - if (eq) - *eq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, - enum res_cq_states state, struct res_cq **cq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_cq *r; - int err; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_CQ_BUSY: - err = -EBUSY; - break; - - case RES_CQ_ALLOCATED: - if (r->com.state != RES_CQ_HW) - err = -EINVAL; - else if (atomic_read(&r->ref_count)) - err = -EBUSY; - else - err = 0; - break; - - case RES_CQ_HW: - if (r->com.state != RES_CQ_ALLOCATED) - err = -EINVAL; - else - err = 0; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_CQ_BUSY; - if (cq) - *cq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_srq_states state, struct res_srq **srq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_srq *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_SRQ_BUSY: - err = -EINVAL; - break; - - case RES_SRQ_ALLOCATED: - if (r->com.state != RES_SRQ_HW) - err = -EINVAL; - else if (atomic_read(&r->ref_count)) - err = -EBUSY; - break; - - case RES_SRQ_HW: - if (r->com.state != RES_SRQ_ALLOCATED) - err = -EINVAL; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_SRQ_BUSY; - if (srq) - *srq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static void res_abort_move(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[type], id); - if (r && (r->owner == slave)) - r->state = r->from_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void res_end_move(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[type], id); - if (r && (r->owner == slave)) - r->state = r->to_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) -{ - return mlx4_is_qp_reserved(dev, qpn) && - (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); -} - -static int fw_reserved(struct mlx4_dev *dev, int qpn) -{ - return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; -} - -static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err; - int count; - int align; - int base; - int qpn; - u8 flags; - - switch (op) { - case RES_OP_RESERVE: - count = get_param_l(&in_param) & 0xffffff; - flags = get_param_l(&in_param) >> 24; - align = get_param_h(&in_param); - err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); - if (err) - return err; - - err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); - if (err) { - mlx4_release_resource(dev, slave, RES_QP, count, 0); - return err; - } - - err = add_res_range(dev, slave, base, count, RES_QP, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_QP, count, 0); - __mlx4_qp_release_range(dev, base, count); - return err; - } - set_param_l(out_param, base); - break; - case RES_OP_MAP_ICM: - qpn = get_param_l(&in_param) & 0x7fffff; - if (valid_reserved(dev, slave, qpn)) { - err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); - if (err) - return err; - } - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, - NULL, 1); - if (err) - return err; - - if (!fw_reserved(dev, qpn)) { - err = __mlx4_qp_alloc_icm(dev, qpn); - if (err) { - res_abort_move(dev, slave, RES_QP, qpn); - return err; - } - } - - res_end_move(dev, slave, RES_QP, qpn); - break; - - default: - err = -EINVAL; - break; - } - return err; -} - -static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int base; - int order; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - order = get_param_l(&in_param); - - err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); - if (err) - return err; - - base = __mlx4_alloc_mtt_range(dev, order); - if (base == -1) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - return -ENOMEM; - } - - err = add_res_range(dev, slave, base, 1, RES_MTT, order); - if (err) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - __mlx4_free_mtt_range(dev, base, order); - } else - set_param_l(out_param, base); - - return err; -} - -static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int index; - int id; - struct res_mpt *mpt; - - switch (op) { - case RES_OP_RESERVE: - err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); - if (err) - break; - - index = __mlx4_mpt_reserve(dev); - if (index == -1) { - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - break; - } - id = index & mpt_mask(dev); - - err = add_res_range(dev, slave, id, 1, RES_MPT, index); - if (err) { - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - __mlx4_mpt_release(dev, index); - break; - } - set_param_l(out_param, index); - break; - case RES_OP_MAP_ICM: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, - RES_MPT_MAPPED, &mpt); - if (err) - return err; - - err = __mlx4_mpt_alloc_icm(dev, mpt->key); - if (err) { - res_abort_move(dev, slave, RES_MPT, id); - return err; - } - - res_end_move(dev, slave, RES_MPT, id); - break; - } - return err; -} - -static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int cqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); - if (err) - break; - - err = __mlx4_cq_alloc_icm(dev, &cqn); - if (err) { - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - break; - } - - err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - __mlx4_cq_free_icm(dev, cqn); - break; - } - - set_param_l(out_param, cqn); - break; - - default: - err = -EINVAL; - } - - return err; -} - -static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int srqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); - if (err) - break; - - err = __mlx4_srq_alloc_icm(dev, &srqn); - if (err) { - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - break; - } - - err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - __mlx4_srq_free_icm(dev, srqn); - break; - } - - set_param_l(out_param, srqn); - break; - - default: - err = -EINVAL; - } - - return err; -} - -static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, - u8 smac_index, u64 *mac) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->smac_index == smac_index && res->port == (u8) port) { - *mac = res->mac; - return 0; - } - } - return -ENOENT; -} - -static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->mac == mac && res->port == (u8) port) { - /* mac found. update ref count */ - ++res->ref_count; - return 0; - } - } - - if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) - return -EINVAL; - res = kzalloc(sizeof *res, GFP_KERNEL); - if (!res) { - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - return -ENOMEM; - } - res->mac = mac; - res->port = (u8) port; - res->smac_index = smac_index; - res->ref_count = 1; - list_add_tail(&res->list, - &tracker->slave_list[slave].res_list[RES_MAC]); - return 0; -} - - -static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->mac == mac && res->port == (u8) port) { - if (!--res->ref_count) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - kfree(res); - } - break; - } - } -} - -static void rem_slave_macs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - int i; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - list_del(&res->list); - /* dereference the mac the num times the slave referenced it */ - for (i = 0; i < res->ref_count; i++) - __mlx4_unregister_mac(dev, res->port, res->mac); - mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); - kfree(res); - } -} - -static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - int err = -EINVAL; - int port; - u64 mac; - u8 smac_index = 0; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - port = !in_port ? get_param_l(out_param) : in_port; - mac = in_param; - - err = __mlx4_register_mac(dev, port, mac); - if (err >= 0) { - smac_index = err; - set_param_l(out_param, err); - err = 0; - } - - if (!err) { - err = mac_add_to_slave(dev, slave, mac, port, smac_index); - if (err) - __mlx4_unregister_mac(dev, port, mac); - } - return err; -} - -static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, - int port, int vlan_index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - if (res->vlan == vlan && res->port == (u8) port) { - /* vlan found. update ref count */ - ++res->ref_count; - return 0; - } - } - - if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) - return -EINVAL; - res = kzalloc(sizeof(*res), GFP_KERNEL); - if (!res) { - mlx4_release_resource(dev, slave, RES_VLAN, 1, port); - return -ENOMEM; - } - res->vlan = vlan; - res->port = (u8) port; - res->vlan_index = vlan_index; - res->ref_count = 1; - list_add_tail(&res->list, - &tracker->slave_list[slave].res_list[RES_VLAN]); - return 0; -} - - -static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - if (res->vlan == vlan && res->port == (u8) port) { - if (!--res->ref_count) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_VLAN, - 1, port); - kfree(res); - } - break; - } - } -} - -static void rem_slave_vlans(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - int i; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - list_del(&res->list); - /* dereference the vlan the num times the slave referenced it */ - for (i = 0; i < res->ref_count; i++) - __mlx4_unregister_vlan(dev, res->port, res->vlan); - mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); - kfree(res); - } -} - -static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - int err = -EINVAL; - u16 vlan; - int vlan_index; - int port; - - port = !in_port ? get_param_l(out_param) : in_port; - - if (!port) - return err; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ - if (!in_port && port > 0 && port <= dev->caps.num_ports) { - slave_state[slave].old_vlan_api = true; - return 0; - } - - vlan = (u16) in_param; - - err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); - if (!err) { - set_param_l(out_param, (u32) vlan_index); - err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); - if (err) - __mlx4_unregister_vlan(dev, port, vlan); - } - return err; -} - -static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - u32 index; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - err = __mlx4_counter_alloc(dev, slave, port, &index); - if (!err) - set_param_l(out_param, index); - - return err; -} - -static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - u32 xrcdn; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - err = __mlx4_xrcd_alloc(dev, &xrcdn); - if (err) - return err; - - err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); - if (err) - __mlx4_xrcd_free(dev, xrcdn); - else - set_param_l(out_param, xrcdn); - - return err; -} - -int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int alop = vhcr->op_modifier; - - switch (vhcr->in_modifier & 0xFF) { - case RES_QP: - err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MTT: - err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MPT: - err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_CQ: - err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_SRQ: - err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MAC: - err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_VLAN: - err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_COUNTER: - err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_XRCD: - err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param) -{ - int err; - int count; - int base; - int qpn; - - switch (op) { - case RES_OP_RESERVE: - base = get_param_l(&in_param) & 0x7fffff; - count = get_param_h(&in_param); - err = rem_res_range(dev, slave, base, count, RES_QP, 0); - if (err) - break; - mlx4_release_resource(dev, slave, RES_QP, count, 0); - __mlx4_qp_release_range(dev, base, count); - break; - case RES_OP_MAP_ICM: - qpn = get_param_l(&in_param) & 0x7fffff; - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, - NULL, 0); - if (err) - return err; - - if (!fw_reserved(dev, qpn)) - __mlx4_qp_free_icm(dev, qpn); - - res_end_move(dev, slave, RES_QP, qpn); - - if (valid_reserved(dev, slave, qpn)) - err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int base; - int order; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - base = get_param_l(&in_param); - order = get_param_h(&in_param); - err = rem_res_range(dev, slave, base, 1, RES_MTT, order); - if (!err) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - __mlx4_free_mtt_range(dev, base, order); - } - return err; -} - -static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param) -{ - int err = -EINVAL; - int index; - int id; - struct res_mpt *mpt; - - switch (op) { - case RES_OP_RESERVE: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = get_res(dev, slave, id, RES_MPT, &mpt); - if (err) - break; - index = mpt->key; - put_res(dev, slave, id, RES_MPT); - - err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); - if (err) - break; - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - __mlx4_mpt_release(dev, index); - break; - case RES_OP_MAP_ICM: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, - RES_MPT_RESERVED, &mpt); - if (err) - return err; - - __mlx4_mpt_free_icm(dev, mpt->key); - res_end_move(dev, slave, RES_MPT, id); - return err; - break; - default: - err = -EINVAL; - break; - } - return err; -} - -static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int cqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - cqn = get_param_l(&in_param); - err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); - if (err) - break; - - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - __mlx4_cq_free_icm(dev, cqn); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int srqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - srqn = get_param_l(&in_param); - err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); - if (err) - break; - - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - __mlx4_srq_free_icm(dev, srqn); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - int port; - int err = 0; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - port = !in_port ? get_param_l(out_param) : in_port; - mac_del_from_slave(dev, slave, in_param, port); - __mlx4_unregister_mac(dev, port, in_param); - break; - default: - err = -EINVAL; - break; - } - - return err; - -} - -static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - int err = 0; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - if (slave_state[slave].old_vlan_api == true) - return 0; - if (!port) - return -EINVAL; - vlan_del_from_slave(dev, slave, in_param, port); - __mlx4_unregister_vlan(dev, port, in_param); - break; - default: - err = -EINVAL; - break; - } - - return err; -} - -static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - int index; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - index = get_param_l(&in_param); - - __mlx4_counter_free(dev, slave, port, index); - - return 0; -} - -static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int xrcdn; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - xrcdn = get_param_l(&in_param); - err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); - if (err) - return err; - - __mlx4_xrcd_free(dev, xrcdn); - - return err; -} - -int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = -EINVAL; - int alop = vhcr->op_modifier; - - switch (vhcr->in_modifier & 0xFF) { - case RES_QP: - err = qp_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param); - break; - - case RES_MTT: - err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MPT: - err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param); - break; - - case RES_CQ: - err = cq_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_SRQ: - err = srq_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MAC: - err = mac_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_VLAN: - err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_COUNTER: - err = counter_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_XRCD: - err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - - default: - break; - } - return err; -} - -/* ugly but other choices are uglier */ -static int mr_phys_mpt(struct mlx4_mpt_entry *mpt) -{ - return (be32_to_cpu(mpt->flags) >> 9) & 1; -} - -static int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) -{ - return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; -} - -static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->mtt_sz); -} - -static u32 mr_get_pd(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; -} - -static int mr_is_fmr(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; -} - -static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; -} - -static int mr_is_region(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; -} - -static int qp_get_mtt_addr(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; -} - -static int srq_get_mtt_addr(struct mlx4_srq_context *srqc) -{ - return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int qp_get_mtt_size(struct mlx4_qp_context *qpc) -{ - int page_shift = (qpc->log_page_size & 0x3f) + 12; - int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; - int log_sq_sride = qpc->sq_size_stride & 7; - int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; - int log_rq_stride = qpc->rq_size_stride & 7; - int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; - int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; - u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; - int sq_size; - int rq_size; - int total_pages; - int total_mem; - int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; - - sq_size = 1 << (log_sq_size + log_sq_sride + 4); - rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); - total_mem = sq_size + rq_size; - total_pages = - roundup_pow_of_two((total_mem + (page_offset << 6)) >> - page_shift); - - return total_pages; -} - -static int check_mtt_range(struct mlx4_dev *dev, int slave, int start, - int size, struct res_mtt *mtt) -{ - int res_start = mtt->com.res_id; - int res_size = (1 << mtt->order); - - if (start < res_start || start + size > res_start + res_size) - return -EPERM; - return 0; -} - -int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mtt *mtt; - struct res_mpt *mpt; - int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; - int phys; - int id; - u32 pd; - int pd_slave; - - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); - if (err) - return err; - - /* Currently disable memory windows since this feature isn't tested yet - * under virtualization. - */ - if (!mr_is_region(inbox->buf)) { - err = -ENOSYS; - goto ex_abort; - } - - /* Make sure that the PD bits related to the slave id are zeros. */ - pd = mr_get_pd(inbox->buf); - pd_slave = (pd >> 17) & 0x7f; - if (pd_slave != 0 && pd_slave != slave) { - err = -EPERM; - goto ex_abort; - } - - if (mr_is_fmr(inbox->buf)) { - /* FMR and Bind Enable are forbidden in slave devices. */ - if (mr_is_bind_enabled(inbox->buf)) { - err = -EPERM; - goto ex_abort; - } - /* FMR and Memory Windows are also forbidden. */ - if (!mr_is_region(inbox->buf)) { - err = -EPERM; - goto ex_abort; - } - } - - phys = mr_phys_mpt(inbox->buf); - if (!phys) { - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - - err = check_mtt_range(dev, slave, mtt_base, - mr_get_mtt_size(inbox->buf), mtt); - if (err) - goto ex_put; - - mpt->mtt = mtt; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put; - - if (!phys) { - atomic_inc(&mtt->ref_count); - put_res(dev, slave, mtt->com.res_id, RES_MTT); - } - - res_end_move(dev, slave, RES_MPT, id); - return 0; - -ex_put: - if (!phys) - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_MPT, id); - - return err; -} - -int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mpt *mpt; - int id; - - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); - if (err) - return err; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - - if (mpt->mtt) - atomic_dec(&mpt->mtt->ref_count); - - res_end_move(dev, slave, RES_MPT, id); - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_MPT, id); - - return err; -} - -int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mpt *mpt; - int id; - - id = index & mpt_mask(dev); - err = get_res(dev, slave, id, RES_MPT, &mpt); - if (err) - return err; - - if (mpt->com.from_state != RES_MPT_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - -out: - put_res(dev, slave, id, RES_MPT); - return err; -} - -static int qp_get_rcqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->cqn_recv) & 0xffffff; -} - -static int qp_get_scqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->cqn_send) & 0xffffff; -} - -static u32 qp_get_srqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->srqn) & 0x1ffffff; -} - -static void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, - struct mlx4_qp_context *context) -{ - u32 qpn = vhcr->in_modifier & 0xffffff; - u32 qkey = 0; - - if (mlx4_get_parav_qkey(dev, qpn, &qkey)) - return; - - /* adjust qkey in qp context */ - context->qkey = cpu_to_be32(qkey); -} - -int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_mtt *mtt; - struct res_qp *qp; - struct mlx4_qp_context *qpc = inbox->buf + 8; - int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; - int mtt_size = qp_get_mtt_size(qpc); - struct res_cq *rcq; - struct res_cq *scq; - int rcqn = qp_get_rcqn(qpc); - int scqn = qp_get_scqn(qpc); - u32 srqn = qp_get_srqn(qpc) & 0xffffff; - int use_srq = (qp_get_srqn(qpc) >> 24) & 1; - struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); - if (err) - return err; - qp->local_qpn = local_qpn; - qp->sched_queue = 0; - qp->param3 = 0; - qp->vlan_control = 0; - qp->fvl_rx = 0; - qp->pri_path_fl = 0; - qp->vlan_index = 0; - qp->feup = 0; - qp->qpc_flags = be32_to_cpu(qpc->flags); - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - - err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); - if (err) - goto ex_put_mtt; - - err = get_res(dev, slave, rcqn, RES_CQ, &rcq); - if (err) - goto ex_put_mtt; - - if (scqn != rcqn) { - err = get_res(dev, slave, scqn, RES_CQ, &scq); - if (err) - goto ex_put_rcq; - } else - scq = rcq; - - if (use_srq) { - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - goto ex_put_scq; - } - - adjust_proxy_tun_qkey(dev, vhcr, qpc); - update_pkey_index(dev, slave, inbox); - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put_srq; - atomic_inc(&mtt->ref_count); - qp->mtt = mtt; - atomic_inc(&rcq->ref_count); - qp->rcq = rcq; - atomic_inc(&scq->ref_count); - qp->scq = scq; - - if (scqn != rcqn) - put_res(dev, slave, scqn, RES_CQ); - - if (use_srq) { - atomic_inc(&srq->ref_count); - put_res(dev, slave, srqn, RES_SRQ); - qp->srq = srq; - } - put_res(dev, slave, rcqn, RES_CQ); - put_res(dev, slave, mtt_base, RES_MTT); - res_end_move(dev, slave, RES_QP, qpn); - - return 0; - -ex_put_srq: - if (use_srq) - put_res(dev, slave, srqn, RES_SRQ); -ex_put_scq: - if (scqn != rcqn) - put_res(dev, slave, scqn, RES_CQ); -ex_put_rcq: - put_res(dev, slave, rcqn, RES_CQ); -ex_put_mtt: - put_res(dev, slave, mtt_base, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_QP, qpn); - - return err; -} - -static int eq_get_mtt_addr(struct mlx4_eq_context *eqc) -{ - return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int eq_get_mtt_size(struct mlx4_eq_context *eqc) -{ - int log_eq_size = eqc->log_eq_size & 0x1f; - int page_shift = (eqc->log_page_size & 0x3f) + 12; - - if (log_eq_size + 5 < page_shift) - return 1; - - return 1 << (log_eq_size + 5 - page_shift); -} - -static int cq_get_mtt_addr(struct mlx4_cq_context *cqc) -{ - return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int cq_get_mtt_size(struct mlx4_cq_context *cqc) -{ - int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; - int page_shift = (cqc->log_page_size & 0x3f) + 12; - - if (log_cq_size + 5 < page_shift) - return 1; - - return 1 << (log_cq_size + 5 - page_shift); -} - -int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int eqn = vhcr->in_modifier; - int res_id = (slave << 8) | eqn; - struct mlx4_eq_context *eqc = inbox->buf; - int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; - int mtt_size = eq_get_mtt_size(eqc); - struct res_eq *eq; - struct res_mtt *mtt; - - err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); - if (err) - return err; - err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); - if (err) - goto out_add; - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto out_move; - - err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); - if (err) - goto out_put; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_put; - - atomic_inc(&mtt->ref_count); - eq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_EQ, res_id); - return 0; - -out_put: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -out_move: - res_abort_move(dev, slave, RES_EQ, res_id); -out_add: - rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); - return err; -} - -static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, - int len, struct res_mtt **res) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_mtt *mtt; - int err = -EINVAL; - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], - com.list) { - if (!check_mtt_range(dev, slave, start, len, mtt)) { - *res = mtt; - mtt->com.from_state = mtt->com.state; - mtt->com.state = RES_MTT_BUSY; - err = 0; - break; - } - } - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int verify_qp_parameters(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *inbox, - enum qp_transition transition, u8 slave) -{ - u32 qp_type; - struct mlx4_qp_context *qp_ctx; - enum mlx4_qp_optpar optpar; - int port; - int num_gids; - - qp_ctx = inbox->buf + 8; - qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; - optpar = be32_to_cpu(*(__be32 *) inbox->buf); - - switch (qp_type) { - case MLX4_QP_ST_RC: - case MLX4_QP_ST_UC: - switch (transition) { - case QP_TRANS_INIT2RTR: - case QP_TRANS_RTR2RTS: - case QP_TRANS_RTS2RTS: - case QP_TRANS_SQD2SQD: - case QP_TRANS_SQD2RTS: - if (slave != mlx4_master_func_num(dev)) - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) - num_gids = mlx4_get_slave_num_gids(dev, slave); - else - num_gids = 1; - if (qp_ctx->pri_path.mgid_index >= num_gids) - return -EINVAL; - } - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { - port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) - num_gids = mlx4_get_slave_num_gids(dev, slave); - else - num_gids = 1; - if (qp_ctx->alt_path.mgid_index >= num_gids) - return -EINVAL; - } - break; - default: - break; - } - - break; - default: - break; - } - - return 0; -} - -int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_mtt mtt; - __be64 *page_list = inbox->buf; - u64 *pg_list = (u64 *)page_list; - int i; - struct res_mtt *rmtt = NULL; - int start = be64_to_cpu(page_list[0]); - int npages = vhcr->in_modifier; - int err; - - err = get_containing_mtt(dev, slave, start, npages, &rmtt); - if (err) - return err; - - /* Call the SW implementation of write_mtt: - * - Prepare a dummy mtt struct - * - Translate inbox contents to simple addresses in host endianness */ - mtt.offset = 0; /* TBD this is broken but I don't handle it since - we don't really use it */ - mtt.order = 0; - mtt.page_shift = 0; - for (i = 0; i < npages; ++i) - pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); - - err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, - ((u64 *)page_list + 2)); - - if (rmtt) - put_res(dev, slave, rmtt->com.res_id, RES_MTT); - - return err; -} - -int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); - struct res_eq *eq; - int err; - - err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); - if (err) - return err; - - err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); - if (err) - goto ex_abort; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put; - - atomic_dec(&eq->mtt->ref_count); - put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_EQ, res_id); - rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); - - return 0; - -ex_put: - put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_EQ, res_id); - - return err; -} - -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; - struct mlx4_cmd_mailbox *mailbox; - u32 in_modifier = 0; - int err; - int res_id; - struct res_eq *req; - - if (!priv->mfunc.master.slave_state) - return -EINVAL; - - /* check for slave valid, slave not PF, and slave active */ - if (slave < 0 || slave >= dev->num_slaves || - slave == dev->caps.function || - !priv->mfunc.master.slave_state[slave].active) - return 0; - - event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; - - /* Create the event only if the slave is registered */ - if (event_eq->eqn < 0) - return 0; - - mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); - res_id = (slave << 8) | event_eq->eqn; - err = get_res(dev, slave, res_id, RES_EQ, &req); - if (err) - goto unlock; - - if (req->com.from_state != RES_EQ_HW) { - err = -EINVAL; - goto put; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto put; - } - - 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_CMD_NATIVE); - - put_res(dev, slave, res_id, RES_EQ); - mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - -put: - put_res(dev, slave, res_id, RES_EQ); - -unlock: - mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); - return err; -} - -int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); - struct res_eq *eq; - int err; - - err = get_res(dev, slave, res_id, RES_EQ, &eq); - if (err) - return err; - - if (eq->com.from_state != RES_EQ_HW) { - err = -EINVAL; - goto ex_put; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - -ex_put: - put_res(dev, slave, res_id, RES_EQ); - return err; -} - -int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int cqn = vhcr->in_modifier; - struct mlx4_cq_context *cqc = inbox->buf; - int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; - struct res_cq *cq; - struct res_mtt *mtt; - - err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); - if (err) - return err; - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto out_move; - err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); - if (err) - goto out_put; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_put; - atomic_inc(&mtt->ref_count); - cq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_CQ, cqn); - return 0; - -out_put: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -out_move: - res_abort_move(dev, slave, RES_CQ, cqn); - return err; -} - -int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int cqn = vhcr->in_modifier; - struct res_cq *cq; - - err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_move; - atomic_dec(&cq->mtt->ref_count); - res_end_move(dev, slave, RES_CQ, cqn); - return 0; - -out_move: - res_abort_move(dev, slave, RES_CQ, cqn); - return err; -} - -int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int cqn = vhcr->in_modifier; - struct res_cq *cq; - int err; - - err = get_res(dev, slave, cqn, RES_CQ, &cq); - if (err) - return err; - - if (cq->com.from_state != RES_CQ_HW) - goto ex_put; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -ex_put: - put_res(dev, slave, cqn, RES_CQ); - - return err; -} - -static int handle_resize(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd, - struct res_cq *cq) -{ - int err; - struct res_mtt *orig_mtt; - struct res_mtt *mtt; - struct mlx4_cq_context *cqc = inbox->buf; - int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; - - err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); - if (err) - return err; - - if (orig_mtt != cq->mtt) { - err = -EINVAL; - goto ex_put; - } - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_put; - - err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); - if (err) - goto ex_put1; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put1; - atomic_dec(&orig_mtt->ref_count); - put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); - atomic_inc(&mtt->ref_count); - cq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - return 0; - -ex_put1: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_put: - put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); - - return err; - -} - -int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int cqn = vhcr->in_modifier; - struct res_cq *cq; - int err; - - err = get_res(dev, slave, cqn, RES_CQ, &cq); - if (err) - return err; - - if (cq->com.from_state != RES_CQ_HW) - goto ex_put; - - if (vhcr->op_modifier == 0) { - err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); - goto ex_put; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -ex_put: - put_res(dev, slave, cqn, RES_CQ); - - return err; -} - -static int srq_get_mtt_size(struct mlx4_srq_context *srqc) -{ - int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; - int log_rq_stride = srqc->logstride & 7; - int page_shift = (srqc->log_page_size & 0x3f) + 12; - - if (log_srq_size + log_rq_stride + 4 < page_shift) - return 1; - - return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); -} - -int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_mtt *mtt; - struct res_srq *srq; - struct mlx4_srq_context *srqc = inbox->buf; - int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; - - if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) - return -EINVAL; - - err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); - if (err) - return err; - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), - mtt); - if (err) - goto ex_put_mtt; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put_mtt; - - atomic_inc(&mtt->ref_count); - srq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_SRQ, srqn); - return 0; - -ex_put_mtt: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_SRQ, srqn); - - return err; -} - -int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - atomic_dec(&srq->mtt->ref_count); - if (srq->cq) - atomic_dec(&srq->cq->ref_count); - res_end_move(dev, slave, RES_SRQ, srqn); - - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_SRQ, srqn); - - return err; -} - -int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - return err; - if (srq->com.from_state != RES_SRQ_HW) { - err = -EBUSY; - goto out; - } - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, srqn, RES_SRQ); - return err; -} - -int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - return err; - - if (srq->com.from_state != RES_SRQ_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, srqn, RES_SRQ); - return err; -} - -int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - - err = get_res(dev, slave, qpn, RES_QP, &qp); - if (err) - return err; - if (qp->com.from_state != RES_QP_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp_context *context = inbox->buf + 8; - adjust_proxy_tun_qkey(dev, vhcr, context); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -static int roce_verify_mac(struct mlx4_dev *dev, int slave, - struct mlx4_qp_context *qpc, - struct mlx4_cmd_mailbox *inbox) -{ - u64 mac; - int port; - u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - u8 sched = *(u8 *)(inbox->buf + 64); - u8 smac_ix; - - port = (sched >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { - smac_ix = qpc->pri_path.grh_mylmc & 0x7f; - if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) - return -ENOENT; - } - return 0; -} - -int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *qpc = inbox->buf + 8; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - u8 orig_sched_queue; - __be32 orig_param3 = qpc->param3; - u8 orig_vlan_control = qpc->pri_path.vlan_control; - u8 orig_fvl_rx = qpc->pri_path.fvl_rx; - u8 orig_pri_path_fl = qpc->pri_path.fl; - u8 orig_vlan_index = qpc->pri_path.vlan_index; - u8 orig_feup = qpc->pri_path.feup; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); - if (err) - return err; - - if (roce_verify_mac(dev, slave, qpc, inbox)) - return -EINVAL; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, qpc); - orig_sched_queue = qpc->pri_path.sched_queue; - - err = get_res(dev, slave, qpn, RES_QP, &qp); - if (err) - return err; - if (qp->com.from_state != RES_QP_HW) { - err = -EBUSY; - goto out; - } - - /* do not modify vport QP params for RSS QPs */ - if (!(qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET))) { - err = update_vport_qp_param(dev, inbox, slave, qpn); - if (err) - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - /* if no error, save sched queue value passed in by VF. This is - * essentially the QOS value provided by the VF. This will be useful - * if we allow dynamic changes from VST back to VGT - */ - if (!err) { - qp->sched_queue = orig_sched_queue; - qp->param3 = orig_param3; - qp->vlan_control = orig_vlan_control; - qp->fvl_rx = orig_fvl_rx; - qp->pri_path_fl = orig_pri_path_fl; - qp->vlan_index = orig_vlan_index; - qp->feup = orig_feup; - } - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); - if (err) - return err; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); - if (err) - return err; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - - -int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp_context *context = inbox->buf + 8; - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); - if (err) - return err; - - adjust_proxy_tun_qkey(dev, vhcr, context); - update_gid(dev, inbox, (u8)slave); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); - if (err) - return err; - - adjust_proxy_tun_qkey(dev, vhcr, context); - update_gid(dev, inbox, (u8)slave); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - - atomic_dec(&qp->mtt->ref_count); - atomic_dec(&qp->rcq->ref_count); - atomic_dec(&qp->scq->ref_count); - if (qp->srq) - atomic_dec(&qp->srq->ref_count); - res_end_move(dev, slave, RES_QP, qpn); - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_QP, qpn); - - return err; -} - -static struct res_gid *find_gid(struct mlx4_dev *dev, int slave, - struct res_qp *rqp, u8 *gid) -{ - struct res_gid *res; - - list_for_each_entry(res, &rqp->mcg_list, list) { - if (!memcmp(res->gid, gid, 16)) - return res; - } - return NULL; -} - -static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, - u8 *gid, enum mlx4_protocol prot, - enum mlx4_steer_type steer, u64 reg_id) -{ - struct res_gid *res; - int err; - - res = kzalloc(sizeof *res, GFP_KERNEL); - if (!res) - return -ENOMEM; - - spin_lock_irq(&rqp->mcg_spl); - if (find_gid(dev, slave, rqp, gid)) { - kfree(res); - err = -EEXIST; - } else { - memcpy(res->gid, gid, 16); - res->prot = prot; - res->steer = steer; - res->reg_id = reg_id; - list_add_tail(&res->list, &rqp->mcg_list); - err = 0; - } - spin_unlock_irq(&rqp->mcg_spl); - - return err; -} - -static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, - u8 *gid, enum mlx4_protocol prot, - enum mlx4_steer_type steer, u64 *reg_id) -{ - struct res_gid *res; - int err; - - spin_lock_irq(&rqp->mcg_spl); - res = find_gid(dev, slave, rqp, gid); - if (!res || res->prot != prot || res->steer != steer) - err = -EINVAL; - else { - *reg_id = res->reg_id; - list_del(&res->list); - kfree(res); - err = 0; - } - spin_unlock_irq(&rqp->mcg_spl); - - return err; -} - -static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type type, u64 *reg_id) -{ - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5], - block_loopback, prot, - reg_id); - case MLX4_STEERING_MODE_B0: - return mlx4_qp_attach_common(dev, qp, gid, - block_loopback, prot, type); - default: - return -EINVAL; - } -} - -static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type type, - u64 reg_id) -{ - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_flow_detach(dev, reg_id); - case MLX4_STEERING_MODE_B0: - return mlx4_qp_detach_common(dev, qp, gid, prot, type); - default: - return -EINVAL; - } -} - -int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp qp; /* dummy for calling attach/detach */ - u8 *gid = inbox->buf; - enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; - int err; - int qpn; - struct res_qp *rqp; - u64 reg_id = 0; - int attach = vhcr->op_modifier; - int block_loopback = vhcr->in_modifier >> 31; - u8 steer_type_mask = 2; - enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; - - qpn = vhcr->in_modifier & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, &rqp); - if (err) - return err; - - qp.qpn = qpn; - if (attach) { - err = qp_attach(dev, &qp, gid, block_loopback, prot, - type, ®_id); - if (err) { - pr_err("Fail to attach rule to qp 0x%x\n", qpn); - goto ex_put; - } - err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); - if (err) - goto ex_detach; - } else { - err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); - if (err) - goto ex_put; - - err = qp_detach(dev, &qp, gid, prot, type, reg_id); - if (err) - pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", - qpn, (unsigned long long)reg_id); - } - put_res(dev, slave, qpn, RES_QP); - return err; - -ex_detach: - qp_detach(dev, &qp, gid, prot, type, reg_id); -ex_put: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -/* - * MAC validation for Flow Steering rules. - * VF can attach rules only with a mac address which is assigned to it. - */ -static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, - struct list_head *rlist) -{ - struct mac_res *res, *tmp; - __be64 be_mac; - - /* make sure it isn't multicast or broadcast mac*/ - if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && - !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { - list_for_each_entry_safe(res, tmp, rlist, list) { - be_mac = cpu_to_be64(res->mac << 16); - if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) - return 0; - } - pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", - eth_header->eth.dst_mac, slave); - return -EINVAL; - } - return 0; -} - -/* - * In case of missing eth header, append eth header with a MAC address - * assigned to the VF. - */ -static int add_eth_header(struct mlx4_dev *dev, int slave, - struct mlx4_cmd_mailbox *inbox, - struct list_head *rlist, int header_id) -{ - struct mac_res *res, *tmp; - u8 port; - struct mlx4_net_trans_rule_hw_ctrl *ctrl; - struct mlx4_net_trans_rule_hw_eth *eth_header; - struct mlx4_net_trans_rule_hw_ipv4 *ip_header; - struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; - __be64 be_mac = 0; - __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); - - ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - port = ctrl->port; - eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); - - /* Clear a space in the inbox for eth header */ - switch (header_id) { - case MLX4_NET_TRANS_RULE_ID_IPV4: - ip_header = - (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); - memmove(ip_header, eth_header, - sizeof(*ip_header) + sizeof(*l4_header)); - break; - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) - (eth_header + 1); - memmove(l4_header, eth_header, sizeof(*l4_header)); - break; - default: - return -EINVAL; - } - list_for_each_entry_safe(res, tmp, rlist, list) { - if (port == res->port) { - be_mac = cpu_to_be64(res->mac << 16); - break; - } - } - if (!be_mac) { - pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", - port); - return -EINVAL; - } - - memset(eth_header, 0, sizeof(*eth_header)); - eth_header->size = sizeof(*eth_header) >> 2; - eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); - memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); - memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); - - return 0; - -} - -int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; - int err; - int qpn; - struct res_qp *rqp; - struct mlx4_net_trans_rule_hw_ctrl *ctrl; - struct _rule_hw *rule_header; - int header_id; - - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - return -EOPNOTSUPP; - - ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, &rqp); - if (err) { - pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); - return err; - } - rule_header = (struct _rule_hw *)(ctrl + 1); - header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); - - switch (header_id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - if (validate_eth_header_mac(slave, rule_header, rlist)) { - err = -EINVAL; - goto err_put; - } - break; - case MLX4_NET_TRANS_RULE_ID_IB: - break; - case MLX4_NET_TRANS_RULE_ID_IPV4: - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); - if (add_eth_header(dev, slave, inbox, rlist, header_id)) { - err = -EINVAL; - goto err_put; - } - vhcr->in_modifier += - sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; - break; - default: - pr_err("Corrupted mailbox.\n"); - err = -EINVAL; - goto err_put; - } - - err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, - vhcr->in_modifier, 0, - MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - goto err_put; - - err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); - if (err) { - mlx4_err(dev, "Fail to add flow steering resources.\n "); - /* detach rule*/ - mlx4_cmd(dev, vhcr->out_param, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - goto err_put; - } - atomic_inc(&rqp->ref_count); -err_put: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct res_qp *rqp; - struct res_fs_rule *rrule; - - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - return -EOPNOTSUPP; - - err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); - if (err) - return err; - /* Release the rule form busy state before removal */ - put_res(dev, slave, vhcr->in_param, RES_FS_RULE); - err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); - if (err) - return err; - - err = mlx4_cmd(dev, vhcr->in_param, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (!err) { - err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, - 0); - atomic_dec(&rqp->ref_count); - - if (err) { - mlx4_err(dev, "Fail to remove flow steering resources.\n "); - goto out; - } - } - -out: - put_res(dev, slave, rrule->qpn, RES_QP); - return err; -} - -enum { - BUSY_MAX_RETRIES = 10 -}; - -int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - - return err; -} - -static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) -{ - struct res_gid *rgid; - struct res_gid *tmp; - struct mlx4_qp qp; /* dummy for calling attach/detach */ - - list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - mlx4_flow_detach(dev, rgid->reg_id); - break; - case MLX4_STEERING_MODE_B0: - qp.qpn = rqp->local_qpn; - (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, - rgid->prot, rgid->steer); - break; - } - list_del(&rgid->list); - kfree(rgid); - } -} - -static int _move_all_busy(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int print) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; - struct res_common *r; - struct res_common *tmp; - int busy; - - busy = 0; - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(r, tmp, rlist, list) { - if (r->owner == slave) { - if (!r->removing) { - if (r->state == RES_ANY_BUSY) { - if (print) - mlx4_dbg(dev, - "%s id 0x%llx is busy\n", - ResourceType(type), - (unsigned long long)r->res_id); - ++busy; - } else { - r->from_state = r->state; - r->state = RES_ANY_BUSY; - r->removing = 1; - } - } - } - } - spin_unlock_irq(mlx4_tlock(dev)); - - return busy; -} - -static int move_all_busy(struct mlx4_dev *dev, int slave, - enum mlx4_resource type) -{ - unsigned long begin; - int busy; - - begin = jiffies; - do { - busy = _move_all_busy(dev, slave, type, 0); - if (time_after(jiffies, begin + 5 * HZ)) - break; - if (busy) - cond_resched(); - } while (busy); - - if (busy) - busy = _move_all_busy(dev, slave, type, 1); - - return busy; -} -static void rem_slave_qps(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *qp_list = - &tracker->slave_list[slave].res_list[RES_QP]; - struct res_qp *qp; - struct res_qp *tmp; - int state; - u64 in_param; - int qpn; - int err; - - err = move_all_busy(dev, slave, RES_QP); - if (err) - mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy" - "for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(qp, tmp, qp_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (qp->com.owner == slave) { - qpn = qp->com.res_id; - detach_qp(dev, slave, qp); - state = qp->com.from_state; - while (state != 0) { - switch (state) { - case RES_QP_RESERVED: - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&qp->com.node, - &tracker->res_tree[RES_QP]); - list_del(&qp->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - if (!valid_reserved(dev, slave, qpn)) { - __mlx4_qp_release_range(dev, qpn, 1); - mlx4_release_resource(dev, slave, - RES_QP, 1, 0); - } - kfree(qp); - state = 0; - break; - case RES_QP_MAPPED: - if (!valid_reserved(dev, slave, qpn)) - __mlx4_qp_free_icm(dev, qpn); - state = RES_QP_RESERVED; - break; - case RES_QP_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, - qp->local_qpn, 2, - MLX4_CMD_2RST_QP, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_qps: failed" - " to move slave %d qpn %d to" - " reset\n", slave, - qp->local_qpn); - atomic_dec(&qp->rcq->ref_count); - atomic_dec(&qp->scq->ref_count); - atomic_dec(&qp->mtt->ref_count); - if (qp->srq) - atomic_dec(&qp->srq->ref_count); - state = RES_QP_MAPPED; - break; - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_srqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *srq_list = - &tracker->slave_list[slave].res_list[RES_SRQ]; - struct res_srq *srq; - struct res_srq *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int srqn; - int err; - - err = move_all_busy(dev, slave, RES_SRQ); - if (err) - mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(srq, tmp, srq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (srq->com.owner == slave) { - srqn = srq->com.res_id; - state = srq->com.from_state; - while (state != 0) { - switch (state) { - case RES_SRQ_ALLOCATED: - __mlx4_srq_free_icm(dev, srqn); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&srq->com.node, - &tracker->res_tree[RES_SRQ]); - list_del(&srq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_SRQ, 1, 0); - kfree(srq); - state = 0; - break; - - case RES_SRQ_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, srqn, 1, - MLX4_CMD_HW2SW_SRQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_srqs: failed" - " to move slave %d srq %d to" - " SW ownership\n", - slave, srqn); - - atomic_dec(&srq->mtt->ref_count); - if (srq->cq) - atomic_dec(&srq->cq->ref_count); - state = RES_SRQ_ALLOCATED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_cqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *cq_list = - &tracker->slave_list[slave].res_list[RES_CQ]; - struct res_cq *cq; - struct res_cq *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int cqn; - int err; - - err = move_all_busy(dev, slave, RES_CQ); - if (err) - mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(cq, tmp, cq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { - cqn = cq->com.res_id; - state = cq->com.from_state; - while (state != 0) { - switch (state) { - case RES_CQ_ALLOCATED: - __mlx4_cq_free_icm(dev, cqn); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&cq->com.node, - &tracker->res_tree[RES_CQ]); - list_del(&cq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_CQ, 1, 0); - kfree(cq); - state = 0; - break; - - case RES_CQ_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, cqn, 1, - MLX4_CMD_HW2SW_CQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_cqs: failed" - " to move slave %d cq %d to" - " SW ownership\n", - slave, cqn); - atomic_dec(&cq->mtt->ref_count); - state = RES_CQ_ALLOCATED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_mrs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mpt_list = - &tracker->slave_list[slave].res_list[RES_MPT]; - struct res_mpt *mpt; - struct res_mpt *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int mptn; - int err; - - err = move_all_busy(dev, slave, RES_MPT); - if (err) - mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (mpt->com.owner == slave) { - mptn = mpt->com.res_id; - state = mpt->com.from_state; - while (state != 0) { - switch (state) { - case RES_MPT_RESERVED: - __mlx4_mpt_release(dev, mpt->key); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&mpt->com.node, - &tracker->res_tree[RES_MPT]); - list_del(&mpt->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_MPT, 1, 0); - kfree(mpt); - state = 0; - break; - - case RES_MPT_MAPPED: - __mlx4_mpt_free_icm(dev, mpt->key); - state = RES_MPT_RESERVED; - break; - - case RES_MPT_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, mptn, 0, - MLX4_CMD_HW2SW_MPT, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_mrs: failed" - " to move slave %d mpt %d to" - " SW ownership\n", - slave, mptn); - if (mpt->mtt) - atomic_dec(&mpt->mtt->ref_count); - state = RES_MPT_MAPPED; - break; - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_mtts(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *mtt_list = - &tracker->slave_list[slave].res_list[RES_MTT]; - struct res_mtt *mtt; - struct res_mtt *tmp; - int state; - LIST_HEAD(tlist); - int base; - int err; - - err = move_all_busy(dev, slave, RES_MTT); - if (err) - mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (mtt->com.owner == slave) { - base = mtt->com.res_id; - state = mtt->com.from_state; - while (state != 0) { - switch (state) { - case RES_MTT_ALLOCATED: - __mlx4_free_mtt_range(dev, base, - mtt->order); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&mtt->com.node, - &tracker->res_tree[RES_MTT]); - list_del(&mtt->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, RES_MTT, - 1 << mtt->order, 0); - kfree(mtt); - state = 0; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *fs_rule_list = - &tracker->slave_list[slave].res_list[RES_FS_RULE]; - struct res_fs_rule *fs_rule; - struct res_fs_rule *tmp; - int state; - u64 base; - int err; - - err = move_all_busy(dev, slave, RES_FS_RULE); - if (err) - mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", - slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (fs_rule->com.owner == slave) { - base = fs_rule->com.res_id; - state = fs_rule->com.from_state; - while (state != 0) { - switch (state) { - case RES_FS_RULE_ALLOCATED: - /* detach rule */ - err = mlx4_cmd(dev, base, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&fs_rule->com.node, - &tracker->res_tree[RES_FS_RULE]); - list_del(&fs_rule->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - kfree(fs_rule); - state = 0; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_eqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *eq_list = - &tracker->slave_list[slave].res_list[RES_EQ]; - struct res_eq *eq; - struct res_eq *tmp; - int err; - int state; - LIST_HEAD(tlist); - int eqn; - struct mlx4_cmd_mailbox *mailbox; - - err = move_all_busy(dev, slave, RES_EQ); - if (err) - mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(eq, tmp, eq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (eq->com.owner == slave) { - eqn = eq->com.res_id; - state = eq->com.from_state; - while (state != 0) { - switch (state) { - case RES_EQ_RESERVED: - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&eq->com.node, - &tracker->res_tree[RES_EQ]); - list_del(&eq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - kfree(eq); - state = 0; - break; - - case RES_EQ_HW: - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - cond_resched(); - continue; - } - err = mlx4_cmd_box(dev, slave, 0, - eqn & 0xff, 0, - MLX4_CMD_HW2SW_EQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_eqs: failed" - " to move slave %d eqs %d to" - " SW ownership\n", slave, eqn); - mlx4_free_cmd_mailbox(dev, mailbox); - atomic_dec(&eq->mtt->ref_count); - state = RES_EQ_RESERVED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_counters(struct mlx4_dev *dev, int slave) -{ - __mlx4_slave_counters_free(dev, slave); -} - -static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *xrcdn_list = - &tracker->slave_list[slave].res_list[RES_XRCD]; - struct res_xrcdn *xrcd; - struct res_xrcdn *tmp; - int err; - int xrcdn; - - err = move_all_busy(dev, slave, RES_XRCD); - if (err) - mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { - if (xrcd->com.owner == slave) { - xrcdn = xrcd->com.res_id; - rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); - list_del(&xrcd->com.list); - kfree(xrcd); - __mlx4_xrcd_free(dev, xrcdn); - } - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); - rem_slave_macs(dev, slave); - rem_slave_vlans(dev, slave); - rem_slave_fs_rule(dev, slave); - rem_slave_qps(dev, slave); - rem_slave_srqs(dev, slave); - rem_slave_cqs(dev, slave); - rem_slave_mrs(dev, slave); - rem_slave_eqs(dev, slave); - rem_slave_mtts(dev, slave); - rem_slave_counters(dev, slave); - rem_slave_xrcdns(dev, slave); - mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); -} - -void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) -{ - struct mlx4_vf_immed_vlan_work *work = - container_of(_work, struct mlx4_vf_immed_vlan_work, work); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_update_qp_context *upd_context; - struct mlx4_dev *dev = &work->priv->dev; - struct mlx4_resource_tracker *tracker = - &work->priv->mfunc.master.res_tracker; - struct list_head *qp_list = - &tracker->slave_list[work->slave].res_list[RES_QP]; - struct res_qp *qp; - struct res_qp *tmp; - u64 qp_path_mask_vlan_ctrl = - ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); - - u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | - (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | - (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); - - int err; - int port, errors = 0; - u8 vlan_control; - - if (mlx4_is_slave(dev)) { - mlx4_warn(dev, "Trying to update-qp in slave %d\n", - work->slave); - goto out; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - goto out; - - if (!work->vlan_id) - vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; - else - vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; - - upd_context = mailbox->buf; - upd_context->qp_mask = cpu_to_be64(MLX4_UPD_QP_MASK_VSD); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(qp, tmp, qp_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (qp->com.owner == work->slave) { - if (qp->com.from_state != RES_QP_HW || - !qp->sched_queue || /* no INIT2RTR trans yet */ - mlx4_is_qp_reserved(dev, qp->local_qpn) || - qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { - spin_lock_irq(mlx4_tlock(dev)); - continue; - } - port = (qp->sched_queue >> 6 & 1) + 1; - if (port != work->port) { - spin_lock_irq(mlx4_tlock(dev)); - continue; - } - if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) - upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); - else - upd_context->primary_addr_path_mask = - cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); - if (work->vlan_id == MLX4_VGT) { - upd_context->qp_context.param3 = qp->param3; - upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; - upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; - upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; - upd_context->qp_context.pri_path.fl = qp->pri_path_fl; - upd_context->qp_context.pri_path.feup = qp->feup; - upd_context->qp_context.pri_path.sched_queue = - qp->sched_queue; - } else { - upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); - upd_context->qp_context.pri_path.vlan_control = vlan_control; - upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; - upd_context->qp_context.pri_path.fvl_rx = - qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; - upd_context->qp_context.pri_path.fl = - qp->pri_path_fl | MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; - upd_context->qp_context.pri_path.feup = - qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; - upd_context->qp_context.pri_path.sched_queue = - qp->sched_queue & 0xC7; - upd_context->qp_context.pri_path.sched_queue |= - ((work->qos & 0x7) << 3); - } - - err = mlx4_cmd(dev, mailbox->dma, - qp->local_qpn & 0xffffff, - 0, MLX4_CMD_UPDATE_QP, - MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (err) { - mlx4_info(dev, "UPDATE_QP failed for slave %d, " - "port %d, qpn %d (%d)\n", - work->slave, port, qp->local_qpn, - err); - errors++; - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_free_cmd_mailbox(dev, mailbox); - - if (errors) - mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", - errors, work->slave, work->port); - - /* unregister previous vlan_id if needed and we had no errors - * while updating the QPs - */ - if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && - NO_INDX != work->orig_vlan_ix) - __mlx4_unregister_vlan(&work->priv->dev, work->port, - work->orig_vlan_id); -out: - kfree(work); - return; -} - diff --git a/sys/ofed/drivers/net/mlx4/sense.c b/sys/ofed/drivers/net/mlx4/sense.c deleted file mode 100644 index 3615e6513e9f..000000000000 --- a/sys/ofed/drivers/net/mlx4/sense.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <linux/errno.h> -#include <linux/if_ether.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" - -int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type) -{ - u64 out_param; - int err = 0; - - err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, - MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) { - mlx4_err(dev, "Sense command failed for port: %d\n", port); - return err; - } - - if (out_param > 2) { - mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", (unsigned long long)out_param); - return -EINVAL; - } - - *type = out_param; - return 0; -} - -void mlx4_do_sense_ports(struct mlx4_dev *dev, - enum mlx4_port_type *stype, - enum mlx4_port_type *defaults) -{ - struct mlx4_sense *sense = &mlx4_priv(dev)->sense; - int err; - int i; - - for (i = 1; i <= dev->caps.num_ports; i++) { - stype[i - 1] = 0; - if (sense->do_sense_port[i] && sense->sense_allowed[i] && - dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { - err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); - if (err) - stype[i - 1] = defaults[i - 1]; - } else - stype[i - 1] = defaults[i - 1]; - } - - /* - * If sensed nothing, remain in current configuration. - */ - for (i = 0; i < dev->caps.num_ports; i++) - stype[i] = stype[i] ? stype[i] : defaults[i]; - -} - -static void mlx4_sense_port(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, - sense_poll); - struct mlx4_dev *dev = sense->dev; - struct mlx4_priv *priv = mlx4_priv(dev); - enum mlx4_port_type stype[MLX4_MAX_PORTS]; - - mutex_lock(&priv->port_mutex); - mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); - - if (mlx4_check_port_params(dev, stype)) - goto sense_again; - - if (mlx4_change_port_types(dev, stype)) - mlx4_err(dev, "Failed to change port_types\n"); - -sense_again: - mutex_unlock(&priv->port_mutex); - queue_delayed_work(mlx4_wq , &sense->sense_poll, - round_jiffies_relative(MLX4_SENSE_RANGE)); -} - -void mlx4_start_sense(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_sense *sense = &priv->sense; - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) - return; - - queue_delayed_work(mlx4_wq , &sense->sense_poll, - round_jiffies_relative(MLX4_SENSE_RANGE)); -} - -void mlx4_stop_sense(struct mlx4_dev *dev) -{ - cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll); -} - -void mlx4_sense_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_sense *sense = &priv->sense; - int port; - - sense->dev = dev; - for (port = 1; port <= dev->caps.num_ports; port++) - sense->do_sense_port[port] = 1; - - INIT_DEFERRABLE_WORK(&sense->sense_poll, mlx4_sense_port); -} diff --git a/sys/ofed/drivers/net/mlx4/srq.c b/sys/ofed/drivers/net/mlx4/srq.c deleted file mode 100644 index fcb6255c7e62..000000000000 --- a/sys/ofed/drivers/net/mlx4/srq.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/srq.h> -#include <linux/module.h> -#include <linux/gfp.h> - -#include "mlx4.h" -#include "icm.h" - -void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_srq *srq; - - spin_lock(&srq_table->lock); - - srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1)); - if (srq) - atomic_inc(&srq->refcount); - - spin_unlock(&srq_table->lock); - - if (!srq) { - mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn); - return; - } - - srq->event(srq, event_type); - - if (atomic_dec_and_test(&srq->refcount)) - complete(&srq->free); -} - -static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd(dev, mailbox->dma, srq_num, 0, - MLX4_CMD_SW2HW_SRQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num, - mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark) -{ - return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); -} - -static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - - *srqn = mlx4_bitmap_alloc(&srq_table->bitmap); - if (*srqn == -1) - return -ENOMEM; - - err = mlx4_table_get(dev, &srq_table->table, *srqn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn); - if (err) - goto err_put; - return 0; - -err_put: - mlx4_table_put(dev, &srq_table->table, *srqn); - -err_out: - mlx4_bitmap_free(&srq_table->bitmap, *srqn, MLX4_NO_RR); - return err; -} - -static int mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, RES_SRQ, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - *srqn = get_param_l(&out_param); - - return err; - } - return __mlx4_srq_alloc_icm(dev, srqn); -} - -void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - - mlx4_table_put(dev, &srq_table->cmpt_table, srqn); - mlx4_table_put(dev, &srq_table->table, srqn); - mlx4_bitmap_free(&srq_table->bitmap, srqn, MLX4_NO_RR); -} - -static void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, srqn); - if (mlx4_cmd(dev, in_param, RES_SRQ, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed freeing cq:%d\n", srqn); - return; - } - __mlx4_srq_free_icm(dev, srqn); -} - -int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, - struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_srq_context *srq_context; - u64 mtt_addr; - int err; - - err = mlx4_srq_alloc_icm(dev, &srq->srqn); - if (err) - return err; - - spin_lock_irq(&srq_table->lock); - err = radix_tree_insert(&srq_table->tree, srq->srqn, srq); - spin_unlock_irq(&srq_table->lock); - if (err) - goto err_icm; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_radix; - } - - srq_context = mailbox->buf; - memset(srq_context, 0, sizeof *srq_context); - - srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) | - srq->srqn); - srq_context->logstride = srq->wqe_shift - 4; - srq_context->xrcd = cpu_to_be16(xrcd); - srq_context->pg_offset_cqn = cpu_to_be32(cqn & 0xffffff); - srq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, mtt); - srq_context->mtt_base_addr_h = mtt_addr >> 32; - srq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - srq_context->pd = cpu_to_be32(pdn); - srq_context->db_rec_addr = cpu_to_be64(db_rec); - - err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - goto err_radix; - - atomic_set(&srq->refcount, 1); - init_completion(&srq->free); - - return 0; - -err_radix: - spin_lock_irq(&srq_table->lock); - radix_tree_delete(&srq_table->tree, srq->srqn); - spin_unlock_irq(&srq_table->lock); - -err_icm: - mlx4_srq_free_icm(dev, srq->srqn); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_srq_alloc); - -void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn); - if (err) - mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn); - - spin_lock_irq(&srq_table->lock); - radix_tree_delete(&srq_table->tree, srq->srqn); - spin_unlock_irq(&srq_table->lock); - - if (atomic_dec_and_test(&srq->refcount)) - complete(&srq->free); - wait_for_completion(&srq->free); - - mlx4_srq_free_icm(dev, srq->srqn); -} -EXPORT_SYMBOL_GPL(mlx4_srq_free); - -int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark) -{ - return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark); -} -EXPORT_SYMBOL_GPL(mlx4_srq_arm); - -int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_srq_context *srq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - srq_context = mailbox->buf; - - err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); - if (err) - goto err_out; - *limit_watermark = be16_to_cpu(srq_context->limit_watermark); - -err_out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_srq_query); - -int mlx4_init_srq_table(struct mlx4_dev *dev) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - spin_lock_init(&srq_table->lock); - INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs, - dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0); - if (err) - return err; - - return 0; -} - -void mlx4_cleanup_srq_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap); -} - -struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_srq *srq; - unsigned long flags; - - spin_lock_irqsave(&srq_table->lock, flags); - srq = radix_tree_lookup(&srq_table->tree, - srqn & (dev->caps.num_srqs - 1)); - spin_unlock_irqrestore(&srq_table->lock, flags); - - return srq; -} -EXPORT_SYMBOL_GPL(mlx4_srq_lookup); diff --git a/sys/ofed/drivers/net/mlx4/sys_tune.c b/sys/ofed/drivers/net/mlx4/sys_tune.c deleted file mode 100644 index 87eb30e6ccfe..000000000000 --- a/sys/ofed/drivers/net/mlx4/sys_tune.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2010, 2014 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <linux/sched.h> -#include <linux/mutex.h> -#include <asm/atomic.h> - -#include "mlx4.h" - -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - -/* Each CPU is put into a group. In most cases, the group number is - * equal to the CPU number of one of the CPUs in the group. The - * exception is group NR_CPUS which is the default group. This is - * protected by sys_tune_startup_mutex. */ -DEFINE_PER_CPU(int, idle_cpu_group) = NR_CPUS; - -/* For each group, a count of the number of CPUs in the group which - * are known to be busy. A busy CPU might be running the busy loop - * below or general kernel code. The count is decremented on entry to - * the old pm_idle handler and incremented on exit. The aim is to - * avoid the count going to zero or negative. This situation can - * occur temporarily during module unload or CPU hot-plug but - * normality will be restored when the affected CPUs next exit the - * idle loop. */ -static atomic_t busy_cpu_count[NR_CPUS+1]; - -/* A workqueue item to be executed to cause the CPU to exit from the - * idle loop. */ -DEFINE_PER_CPU(struct work_struct, sys_tune_cpu_work); - -#define sys_tune_set_state(CPU,STATE) \ - do { } while(0) - - -/* A mutex to protect most of the module datastructures. */ -static DEFINE_MUTEX(sys_tune_startup_mutex); - -/* The old pm_idle handler. */ -static void (*old_pm_idle)(void) = NULL; - -static void sys_tune_pm_idle(void) -{ - atomic_t *busy_cpus_ptr; - int busy_cpus; - int cpu = smp_processor_id(); - - busy_cpus_ptr = &(busy_cpu_count[per_cpu(idle_cpu_group, cpu)]); - - sys_tune_set_state(cpu, 2); - - local_irq_enable(); - while (!need_resched()) { - busy_cpus = atomic_read(busy_cpus_ptr); - - /* If other CPUs in this group are busy then let this - * CPU go idle. We mustn't let the number of busy - * CPUs drop below 1. */ - if ( busy_cpus > 1 && - old_pm_idle != NULL && - ( atomic_cmpxchg(busy_cpus_ptr, busy_cpus, - busy_cpus-1) == busy_cpus ) ) { - local_irq_disable(); - sys_tune_set_state(cpu, 3); - /* This check might not be necessary, but it - * seems safest to include it because there - * might be a kernel version which requires - * it. */ - if (need_resched()) - local_irq_enable(); - else - old_pm_idle(); - /* This CPU is busy again. */ - sys_tune_set_state(cpu, 1); - atomic_add(1, busy_cpus_ptr); - return; - } - - cpu_relax(); - } - sys_tune_set_state(cpu, 0); -} - - -void sys_tune_work_func(struct work_struct *work) -{ - /* Do nothing. Since this function is running in process - * context, the idle thread isn't running on this CPU. */ -} - - -#ifdef CONFIG_SMP -static void sys_tune_smp_call(void *info) -{ - schedule_work(&get_cpu_var(sys_tune_cpu_work)); - put_cpu_var(sys_tune_cpu_work); -} -#endif - - -#ifdef CONFIG_SMP -static void sys_tune_refresh(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) - on_each_cpu(&sys_tune_smp_call, NULL, 0, 1); -#else - on_each_cpu(&sys_tune_smp_call, NULL, 1); -#endif -} -#else -static void sys_tune_refresh(void) -{ - /* The current thread is executing on the one and only CPU so - * the idle thread isn't running. */ -} -#endif - - - -static int sys_tune_cpu_group(int cpu) -{ -#ifdef CONFIG_SMP - const cpumask_t *mask; - int other_cpu; - int group; - -#if defined(topology_thread_cpumask) && defined(ST_HAVE_EXPORTED_CPU_SIBLING_MAP) - /* Keep one hyperthread busy per core. */ - mask = topology_thread_cpumask(cpu); -#else - return cpu; -#endif - for_each_cpu_mask(cpu, *(mask)) { - group = per_cpu(idle_cpu_group, other_cpu); - if (group != NR_CPUS) - return group; - } -#endif - - return cpu; -} - - -static void sys_tune_add_cpu(int cpu) -{ - int group; - - /* Do nothing if this CPU has already been added. */ - if (per_cpu(idle_cpu_group, cpu) != NR_CPUS) - return; - - group = sys_tune_cpu_group(cpu); - per_cpu(idle_cpu_group, cpu) = group; - atomic_inc(&(busy_cpu_count[group])); - -} - -static void sys_tune_del_cpu(int cpu) -{ - - int group; - - if (per_cpu(idle_cpu_group, cpu) == NR_CPUS) - return; - - group = per_cpu(idle_cpu_group, cpu); - /* If the CPU was busy, this can cause the count to drop to - * zero. To rectify this, we need to cause one of the other - * CPUs in the group to exit the idle loop. If the CPU was - * not busy then this causes the contribution for this CPU to - * go to -1 which can cause the overall count to drop to zero - * or go negative. To rectify this situation we need to cause - * this CPU to exit the idle loop. */ - atomic_dec(&(busy_cpu_count[group])); - per_cpu(idle_cpu_group, cpu) = NR_CPUS; - -} - - -static int sys_tune_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - int cpu = (long)hcpu; - - switch(action) { -#ifdef CPU_ONLINE_FROZEN - case CPU_ONLINE_FROZEN: -#endif - case CPU_ONLINE: - mutex_lock(&sys_tune_startup_mutex); - sys_tune_add_cpu(cpu); - mutex_unlock(&sys_tune_startup_mutex); - /* The CPU might have already entered the idle loop in - * the wrong group. Make sure it exits the idle loop - * so that it picks up the correct group. */ - sys_tune_refresh(); - break; - -#ifdef CPU_DEAD_FROZEN - case CPU_DEAD_FROZEN: -#endif - case CPU_DEAD: - mutex_lock(&sys_tune_startup_mutex); - sys_tune_del_cpu(cpu); - mutex_unlock(&sys_tune_startup_mutex); - /* The deleted CPU may have been the only busy CPU in - * the group. Make sure one of the other CPUs in the - * group exits the idle loop. */ - sys_tune_refresh(); - break; - } - return NOTIFY_OK; -} - - -static struct notifier_block sys_tune_cpu_nb = { - .notifier_call = sys_tune_cpu_notify, -}; - - -static void sys_tune_ensure_init(void) -{ - BUG_ON (old_pm_idle != NULL); - - /* Atomically update pm_idle to &sys_tune_pm_idle. The old value - * is stored in old_pm_idle before installing the new - * handler. */ - do { - old_pm_idle = pm_idle; - } while (cmpxchg(&pm_idle, old_pm_idle, &sys_tune_pm_idle) != - old_pm_idle); -} -#endif - -void sys_tune_fini(void) -{ -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - void (*old)(void); - int cpu; - - unregister_cpu_notifier(&sys_tune_cpu_nb); - - mutex_lock(&sys_tune_startup_mutex); - - - old = cmpxchg(&pm_idle, &sys_tune_pm_idle, old_pm_idle); - - for_each_online_cpu(cpu) - sys_tune_del_cpu(cpu); - - mutex_unlock(&sys_tune_startup_mutex); - - /* Our handler may still be executing on other CPUs. - * Schedule this thread on all CPUs to make sure all - * idle threads get interrupted. */ - sys_tune_refresh(); - - /* Make sure the work item has finished executing on all CPUs. - * This in turn ensures that all idle threads have been - * interrupted. */ - flush_scheduled_work(); -#endif /* CONFIG_X86 */ -} - -void sys_tune_init(void) -{ -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - int cpu; - - for_each_possible_cpu(cpu) { - INIT_WORK(&per_cpu(sys_tune_cpu_work, cpu), - sys_tune_work_func); - } - - /* Start by registering the handler to ensure we don't miss - * any updates. */ - register_cpu_notifier(&sys_tune_cpu_nb); - - mutex_lock(&sys_tune_startup_mutex); - - for_each_online_cpu(cpu) - sys_tune_add_cpu(cpu); - - sys_tune_ensure_init(); - - - mutex_unlock(&sys_tune_startup_mutex); - - /* Ensure our idle handler starts to run. */ - sys_tune_refresh(); -#endif -} - |