You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
mlx5: Add driver for Mellanox Connect-IB adapters
The driver is comprised of two kernel modules: mlx5_ib and mlx5_core. This partitioning resembles what we have for mlx4, except that mlx5_ib is the pci device driver and not mlx5_core. mlx5_core is essentially a library that provides general functionality that is intended to be used by other Mellanox devices that will be introduced in the future. mlx5_ib has a similar role as any hardware device under drivers/infiniband/hw. Signed-off-by: Eli Cohen <eli@mellanox.com> Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> [ Merge in coccinelle fixes from Fengguang Wu <fengguang.wu@intel.com>. - Roland ] Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
22
MAINTAINERS
22
MAINTAINERS
@@ -5365,6 +5365,28 @@ W: http://linuxtv.org
|
||||
S: Odd Fixes
|
||||
F: drivers/media/radio/radio-miropcm20*
|
||||
|
||||
Mellanox MLX5 core VPI driver
|
||||
M: Eli Cohen <eli@mellanox.com>
|
||||
L: netdev@vger.kernel.org
|
||||
L: linux-rdma@vger.kernel.org
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
Q: http://patchwork.kernel.org/project/linux-rdma/list/
|
||||
T: git://openfabrics.org/~eli/connect-ib.git
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/mellanox/mlx5/core/
|
||||
F: include/linux/mlx5/
|
||||
|
||||
Mellanox MLX5 IB driver
|
||||
M: Eli Cohen <eli@mellanox.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
W: http://www.mellanox.com
|
||||
Q: http://patchwork.kernel.org/project/linux-rdma/list/
|
||||
T: git://openfabrics.org/~eli/connect-ib.git
|
||||
S: Supported
|
||||
F: include/linux/mlx5/
|
||||
F: drivers/infiniband/hw/mlx5/
|
||||
|
||||
MODULE SUPPORT
|
||||
M: Rusty Russell <rusty@rustcorp.com.au>
|
||||
S: Maintained
|
||||
|
||||
@@ -50,6 +50,7 @@ source "drivers/infiniband/hw/amso1100/Kconfig"
|
||||
source "drivers/infiniband/hw/cxgb3/Kconfig"
|
||||
source "drivers/infiniband/hw/cxgb4/Kconfig"
|
||||
source "drivers/infiniband/hw/mlx4/Kconfig"
|
||||
source "drivers/infiniband/hw/mlx5/Kconfig"
|
||||
source "drivers/infiniband/hw/nes/Kconfig"
|
||||
source "drivers/infiniband/hw/ocrdma/Kconfig"
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
|
||||
obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
|
||||
obj-$(CONFIG_INFINIBAND_CXGB4) += hw/cxgb4/
|
||||
obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/
|
||||
obj-$(CONFIG_MLX5_INFINIBAND) += hw/mlx5/
|
||||
obj-$(CONFIG_INFINIBAND_NES) += hw/nes/
|
||||
obj-$(CONFIG_INFINIBAND_OCRDMA) += hw/ocrdma/
|
||||
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
|
||||
|
||||
10
drivers/infiniband/hw/mlx5/Kconfig
Normal file
10
drivers/infiniband/hw/mlx5/Kconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
config MLX5_INFINIBAND
|
||||
tristate "Mellanox Connect-IB HCA support"
|
||||
depends on NETDEVICES && ETHERNET && PCI && X86
|
||||
select NET_VENDOR_MELLANOX
|
||||
select MLX5_CORE
|
||||
---help---
|
||||
This driver provides low-level InfiniBand support for
|
||||
Mellanox Connect-IB PCI Express host channel adapters (HCAs).
|
||||
This is required to use InfiniBand protocols such as
|
||||
IP-over-IB or SRP with these devices.
|
||||
3
drivers/infiniband/hw/mlx5/Makefile
Normal file
3
drivers/infiniband/hw/mlx5/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_MLX5_INFINIBAND) += mlx5_ib.o
|
||||
|
||||
mlx5_ib-y := main.o cq.o doorbell.o qp.o mem.o srq.o mr.o ah.o mad.o
|
||||
92
drivers/infiniband/hw/mlx5/ah.c
Normal file
92
drivers/infiniband/hw/mlx5/ah.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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 "mlx5_ib.h"
|
||||
|
||||
struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr,
|
||||
struct mlx5_ib_ah *ah)
|
||||
{
|
||||
if (ah_attr->ah_flags & IB_AH_GRH) {
|
||||
memcpy(ah->av.rgid, &ah_attr->grh.dgid, 16);
|
||||
ah->av.grh_gid_fl = cpu_to_be32(ah_attr->grh.flow_label |
|
||||
(1 << 30) |
|
||||
ah_attr->grh.sgid_index << 20);
|
||||
ah->av.hop_limit = ah_attr->grh.hop_limit;
|
||||
ah->av.tclass = ah_attr->grh.traffic_class;
|
||||
}
|
||||
|
||||
ah->av.rlid = cpu_to_be16(ah_attr->dlid);
|
||||
ah->av.fl_mlid = ah_attr->src_path_bits & 0x7f;
|
||||
ah->av.stat_rate_sl = (ah_attr->static_rate << 4) | (ah_attr->sl & 0xf);
|
||||
|
||||
return &ah->ibah;
|
||||
}
|
||||
|
||||
struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
|
||||
{
|
||||
struct mlx5_ib_ah *ah;
|
||||
|
||||
ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
|
||||
if (!ah)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return create_ib_ah(ah_attr, ah); /* never fails */
|
||||
}
|
||||
|
||||
int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
|
||||
{
|
||||
struct mlx5_ib_ah *ah = to_mah(ibah);
|
||||
u32 tmp;
|
||||
|
||||
memset(ah_attr, 0, sizeof(*ah_attr));
|
||||
|
||||
tmp = be32_to_cpu(ah->av.grh_gid_fl);
|
||||
if (tmp & (1 << 30)) {
|
||||
ah_attr->ah_flags = IB_AH_GRH;
|
||||
ah_attr->grh.sgid_index = (tmp >> 20) & 0xff;
|
||||
ah_attr->grh.flow_label = tmp & 0xfffff;
|
||||
memcpy(&ah_attr->grh.dgid, ah->av.rgid, 16);
|
||||
ah_attr->grh.hop_limit = ah->av.hop_limit;
|
||||
ah_attr->grh.traffic_class = ah->av.tclass;
|
||||
}
|
||||
ah_attr->dlid = be16_to_cpu(ah->av.rlid);
|
||||
ah_attr->static_rate = ah->av.stat_rate_sl >> 4;
|
||||
ah_attr->sl = ah->av.stat_rate_sl & 0xf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx5_ib_destroy_ah(struct ib_ah *ah)
|
||||
{
|
||||
kfree(to_mah(ah));
|
||||
return 0;
|
||||
}
|
||||
843
drivers/infiniband/hw/mlx5/cq.c
Normal file
843
drivers/infiniband/hw/mlx5/cq.c
Normal file
File diff suppressed because it is too large
Load Diff
100
drivers/infiniband/hw/mlx5/doorbell.c
Normal file
100
drivers/infiniband/hw/mlx5/doorbell.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
|
||||
#include "mlx5_ib.h"
|
||||
|
||||
struct mlx5_ib_user_db_page {
|
||||
struct list_head list;
|
||||
struct ib_umem *umem;
|
||||
unsigned long user_virt;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
|
||||
struct mlx5_db *db)
|
||||
{
|
||||
struct mlx5_ib_user_db_page *page;
|
||||
struct ib_umem_chunk *chunk;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&context->db_page_mutex);
|
||||
|
||||
list_for_each_entry(page, &context->db_page_list, list)
|
||||
if (page->user_virt == (virt & PAGE_MASK))
|
||||
goto found;
|
||||
|
||||
page = kmalloc(sizeof(*page), GFP_KERNEL);
|
||||
if (!page) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
page->user_virt = (virt & PAGE_MASK);
|
||||
page->refcnt = 0;
|
||||
page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
|
||||
PAGE_SIZE, 0, 0);
|
||||
if (IS_ERR(page->umem)) {
|
||||
err = PTR_ERR(page->umem);
|
||||
kfree(page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_add(&page->list, &context->db_page_list);
|
||||
|
||||
found:
|
||||
chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
|
||||
db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
|
||||
db->u.user_page = page;
|
||||
++page->refcnt;
|
||||
|
||||
out:
|
||||
mutex_unlock(&context->db_page_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db)
|
||||
{
|
||||
mutex_lock(&context->db_page_mutex);
|
||||
|
||||
if (!--db->u.user_page->refcnt) {
|
||||
list_del(&db->u.user_page->list);
|
||||
ib_umem_release(db->u.user_page->umem);
|
||||
kfree(db->u.user_page);
|
||||
}
|
||||
|
||||
mutex_unlock(&context->db_page_mutex);
|
||||
}
|
||||
139
drivers/infiniband/hw/mlx5/mad.c
Normal file
139
drivers/infiniband/hw/mlx5/mad.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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/mlx5/cmd.h>
|
||||
#include <rdma/ib_mad.h>
|
||||
#include <rdma/ib_smi.h>
|
||||
#include "mlx5_ib.h"
|
||||
|
||||
enum {
|
||||
MLX5_IB_VENDOR_CLASS1 = 0x9,
|
||||
MLX5_IB_VENDOR_CLASS2 = 0xa
|
||||
};
|
||||
|
||||
int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
|
||||
int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
|
||||
void *in_mad, void *response_mad)
|
||||
{
|
||||
u8 op_modifier = 0;
|
||||
|
||||
/* Key check traps can't be generated unless we have in_wc to
|
||||
* tell us where to send the trap.
|
||||
*/
|
||||
if (ignore_mkey || !in_wc)
|
||||
op_modifier |= 0x1;
|
||||
if (ignore_bkey || !in_wc)
|
||||
op_modifier |= 0x2;
|
||||
|
||||
return mlx5_core_mad_ifc(&dev->mdev, in_mad, response_mad, op_modifier, port);
|
||||
}
|
||||
|
||||
int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
|
||||
struct ib_wc *in_wc, struct ib_grh *in_grh,
|
||||
struct ib_mad *in_mad, struct ib_mad *out_mad)
|
||||
{
|
||||
u16 slid;
|
||||
int err;
|
||||
|
||||
slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
|
||||
|
||||
if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0)
|
||||
return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
|
||||
|
||||
if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
|
||||
in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
|
||||
if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
|
||||
in_mad->mad_hdr.method != IB_MGMT_METHOD_SET &&
|
||||
in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS)
|
||||
return IB_MAD_RESULT_SUCCESS;
|
||||
|
||||
/* Don't process SMInfo queries -- the SMA can't handle them.
|
||||
*/
|
||||
if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
|
||||
return IB_MAD_RESULT_SUCCESS;
|
||||
} else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
|
||||
in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS1 ||
|
||||
in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS2 ||
|
||||
in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
|
||||
if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
|
||||
in_mad->mad_hdr.method != IB_MGMT_METHOD_SET)
|
||||
return IB_MAD_RESULT_SUCCESS;
|
||||
} else {
|
||||
return IB_MAD_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
err = mlx5_MAD_IFC(to_mdev(ibdev),
|
||||
mad_flags & IB_MAD_IGNORE_MKEY,
|
||||
mad_flags & IB_MAD_IGNORE_BKEY,
|
||||
port_num, in_wc, in_grh, in_mad, out_mad);
|
||||
if (err)
|
||||
return IB_MAD_RESULT_FAILURE;
|
||||
|
||||
/* set return bit in status of directed route responses */
|
||||
if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
|
||||
out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
|
||||
|
||||
if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
|
||||
/* no response for trap repress */
|
||||
return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
|
||||
|
||||
return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
|
||||
}
|
||||
|
||||
int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port)
|
||||
{
|
||||
struct ib_smp *in_mad = NULL;
|
||||
struct ib_smp *out_mad = NULL;
|
||||
int err = -ENOMEM;
|
||||
u16 packet_error;
|
||||
|
||||
in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
|
||||
out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
|
||||
if (!in_mad || !out_mad)
|
||||
goto out;
|
||||
|
||||
init_query_mad(in_mad);
|
||||
in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
|
||||
in_mad->attr_mod = cpu_to_be32(port);
|
||||
|
||||
err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
|
||||
|
||||
packet_error = be16_to_cpu(out_mad->status);
|
||||
|
||||
dev->mdev.caps.ext_port_cap[port - 1] = (!err && !packet_error) ?
|
||||
MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0;
|
||||
|
||||
out:
|
||||
kfree(in_mad);
|
||||
kfree(out_mad);
|
||||
return err;
|
||||
}
|
||||
1504
drivers/infiniband/hw/mlx5/main.c
Normal file
1504
drivers/infiniband/hw/mlx5/main.c
Normal file
File diff suppressed because it is too large
Load Diff
162
drivers/infiniband/hw/mlx5/mem.c
Normal file
162
drivers/infiniband/hw/mlx5/mem.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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/module.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
#include "mlx5_ib.h"
|
||||
|
||||
/* @umem: umem object to scan
|
||||
* @addr: ib virtual address requested by the user
|
||||
* @count: number of PAGE_SIZE pages covered by umem
|
||||
* @shift: page shift for the compound pages found in the region
|
||||
* @ncont: number of compund pages
|
||||
* @order: log2 of the number of compound pages
|
||||
*/
|
||||
void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
|
||||
int *ncont, int *order)
|
||||
{
|
||||
struct ib_umem_chunk *chunk;
|
||||
unsigned long tmp;
|
||||
unsigned long m;
|
||||
int i, j, k;
|
||||
u64 base = 0;
|
||||
int p = 0;
|
||||
int skip;
|
||||
int mask;
|
||||
u64 len;
|
||||
u64 pfn;
|
||||
|
||||
addr = addr >> PAGE_SHIFT;
|
||||
tmp = (unsigned long)addr;
|
||||
m = find_first_bit(&tmp, sizeof(tmp));
|
||||
skip = 1 << m;
|
||||
mask = skip - 1;
|
||||
i = 0;
|
||||
list_for_each_entry(chunk, &umem->chunk_list, list)
|
||||
for (j = 0; j < chunk->nmap; j++) {
|
||||
len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
|
||||
pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT;
|
||||
for (k = 0; k < len; k++) {
|
||||
if (!(i & mask)) {
|
||||
tmp = (unsigned long)pfn;
|
||||
m = min(m, find_first_bit(&tmp, sizeof(tmp)));
|
||||
skip = 1 << m;
|
||||
mask = skip - 1;
|
||||
base = pfn;
|
||||
p = 0;
|
||||
} else {
|
||||
if (base + p != pfn) {
|
||||
tmp = (unsigned long)p;
|
||||
m = find_first_bit(&tmp, sizeof(tmp));
|
||||
skip = 1 << m;
|
||||
mask = skip - 1;
|
||||
base = pfn;
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m);
|
||||
|
||||
if (order)
|
||||
*order = ilog2(roundup_pow_of_two(i) >> m);
|
||||
|
||||
*ncont = DIV_ROUND_UP(i, (1 << m));
|
||||
} else {
|
||||
m = 0;
|
||||
|
||||
if (order)
|
||||
*order = 0;
|
||||
|
||||
*ncont = 0;
|
||||
}
|
||||
*shift = PAGE_SHIFT + m;
|
||||
*count = i;
|
||||
}
|
||||
|
||||
void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
|
||||
int page_shift, __be64 *pas, int umr)
|
||||
{
|
||||
int shift = page_shift - PAGE_SHIFT;
|
||||
int mask = (1 << shift) - 1;
|
||||
struct ib_umem_chunk *chunk;
|
||||
int i, j, k;
|
||||
u64 cur = 0;
|
||||
u64 base;
|
||||
int len;
|
||||
|
||||
i = 0;
|
||||
list_for_each_entry(chunk, &umem->chunk_list, list)
|
||||
for (j = 0; j < chunk->nmap; j++) {
|
||||
len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
|
||||
base = sg_dma_address(&chunk->page_list[j]);
|
||||
for (k = 0; k < len; k++) {
|
||||
if (!(i & mask)) {
|
||||
cur = base + (k << PAGE_SHIFT);
|
||||
if (umr)
|
||||
cur |= 3;
|
||||
|
||||
pas[i >> shift] = cpu_to_be64(cur);
|
||||
mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n",
|
||||
i >> shift, be64_to_cpu(pas[i >> shift]));
|
||||
} else
|
||||
mlx5_ib_dbg(dev, "=====> 0x%llx\n",
|
||||
base + (k << PAGE_SHIFT));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset)
|
||||
{
|
||||
u64 page_size;
|
||||
u64 page_mask;
|
||||
u64 off_size;
|
||||
u64 off_mask;
|
||||
u64 buf_off;
|
||||
|
||||
page_size = 1 << page_shift;
|
||||
page_mask = page_size - 1;
|
||||
buf_off = addr & page_mask;
|
||||
off_size = page_size >> 6;
|
||||
off_mask = off_size - 1;
|
||||
|
||||
if (buf_off & off_mask)
|
||||
return -EINVAL;
|
||||
|
||||
*offset = buf_off >> ilog2(off_size);
|
||||
return 0;
|
||||
}
|
||||
545
drivers/infiniband/hw/mlx5/mlx5_ib.h
Normal file
545
drivers/infiniband/hw/mlx5/mlx5_ib.h
Normal file
File diff suppressed because it is too large
Load Diff
1007
drivers/infiniband/hw/mlx5/mr.c
Normal file
1007
drivers/infiniband/hw/mlx5/mr.c
Normal file
File diff suppressed because it is too large
Load Diff
2524
drivers/infiniband/hw/mlx5/qp.c
Normal file
2524
drivers/infiniband/hw/mlx5/qp.c
Normal file
File diff suppressed because it is too large
Load Diff
473
drivers/infiniband/hw/mlx5/srq.c
Normal file
473
drivers/infiniband/hw/mlx5/srq.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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/module.h>
|
||||
#include <linux/mlx5/qp.h>
|
||||
#include <linux/mlx5/srq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
|
||||
#include "mlx5_ib.h"
|
||||
#include "user.h"
|
||||
|
||||
/* not supported currently */
|
||||
static int srq_signature;
|
||||
|
||||
static void *get_wqe(struct mlx5_ib_srq *srq, int n)
|
||||
{
|
||||
return mlx5_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
|
||||
}
|
||||
|
||||
static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
|
||||
{
|
||||
struct ib_event event;
|
||||
struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
|
||||
|
||||
if (ibsrq->event_handler) {
|
||||
event.device = ibsrq->device;
|
||||
event.element.srq = ibsrq;
|
||||
switch (type) {
|
||||
case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
|
||||
event.event = IB_EVENT_SRQ_LIMIT_REACHED;
|
||||
break;
|
||||
case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
|
||||
event.event = IB_EVENT_SRQ_ERR;
|
||||
break;
|
||||
default:
|
||||
pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n",
|
||||
type, srq->srqn);
|
||||
return;
|
||||
}
|
||||
|
||||
ibsrq->event_handler(&event, ibsrq->srq_context);
|
||||
}
|
||||
}
|
||||
|
||||
static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
|
||||
struct mlx5_create_srq_mbox_in **in,
|
||||
struct ib_udata *udata, int buf_size, int *inlen)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(pd->device);
|
||||
struct mlx5_ib_create_srq ucmd;
|
||||
int err;
|
||||
int npages;
|
||||
int page_shift;
|
||||
int ncont;
|
||||
u32 offset;
|
||||
|
||||
if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
|
||||
mlx5_ib_dbg(dev, "failed copy udata\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
|
||||
|
||||
srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,
|
||||
0, 0);
|
||||
if (IS_ERR(srq->umem)) {
|
||||
mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size);
|
||||
err = PTR_ERR(srq->umem);
|
||||
return err;
|
||||
}
|
||||
|
||||
mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, &npages,
|
||||
&page_shift, &ncont, NULL);
|
||||
err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift,
|
||||
&offset);
|
||||
if (err) {
|
||||
mlx5_ib_warn(dev, "bad offset\n");
|
||||
goto err_umem;
|
||||
}
|
||||
|
||||
*inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
|
||||
*in = mlx5_vzalloc(*inlen);
|
||||
if (!(*in)) {
|
||||
err = -ENOMEM;
|
||||
goto err_umem;
|
||||
}
|
||||
|
||||
mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0);
|
||||
|
||||
err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context),
|
||||
ucmd.db_addr, &srq->db);
|
||||
if (err) {
|
||||
mlx5_ib_dbg(dev, "map doorbell failed\n");
|
||||
goto err_in;
|
||||
}
|
||||
|
||||
(*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
|
||||
(*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
|
||||
|
||||
return 0;
|
||||
|
||||
err_in:
|
||||
mlx5_vfree(*in);
|
||||
|
||||
err_umem:
|
||||
ib_umem_release(srq->umem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
|
||||
struct mlx5_create_srq_mbox_in **in, int buf_size,
|
||||
int *inlen)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
struct mlx5_wqe_srq_next_seg *next;
|
||||
int page_shift;
|
||||
int npages;
|
||||
|
||||
err = mlx5_db_alloc(&dev->mdev, &srq->db);
|
||||
if (err) {
|
||||
mlx5_ib_warn(dev, "alloc dbell rec failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
*srq->db.db = 0;
|
||||
|
||||
if (mlx5_buf_alloc(&dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
|
||||
mlx5_ib_dbg(dev, "buf alloc failed\n");
|
||||
err = -ENOMEM;
|
||||
goto err_db;
|
||||
}
|
||||
page_shift = srq->buf.page_shift;
|
||||
|
||||
srq->head = 0;
|
||||
srq->tail = srq->msrq.max - 1;
|
||||
srq->wqe_ctr = 0;
|
||||
|
||||
for (i = 0; i < srq->msrq.max; i++) {
|
||||
next = get_wqe(srq, i);
|
||||
next->next_wqe_index =
|
||||
cpu_to_be16((i + 1) & (srq->msrq.max - 1));
|
||||
}
|
||||
|
||||
npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT));
|
||||
mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n",
|
||||
buf_size, page_shift, srq->buf.npages, npages);
|
||||
*inlen = sizeof(**in) + sizeof(*(*in)->pas) * npages;
|
||||
*in = mlx5_vzalloc(*inlen);
|
||||
if (!*in) {
|
||||
err = -ENOMEM;
|
||||
goto err_buf;
|
||||
}
|
||||
mlx5_fill_page_array(&srq->buf, (*in)->pas);
|
||||
|
||||
srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL);
|
||||
if (!srq->wrid) {
|
||||
mlx5_ib_dbg(dev, "kmalloc failed %lu\n",
|
||||
(unsigned long)(srq->msrq.max * sizeof(u64)));
|
||||
err = -ENOMEM;
|
||||
goto err_in;
|
||||
}
|
||||
srq->wq_sig = !!srq_signature;
|
||||
|
||||
(*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
|
||||
|
||||
return 0;
|
||||
|
||||
err_in:
|
||||
mlx5_vfree(*in);
|
||||
|
||||
err_buf:
|
||||
mlx5_buf_free(&dev->mdev, &srq->buf);
|
||||
|
||||
err_db:
|
||||
mlx5_db_free(&dev->mdev, &srq->db);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq)
|
||||
{
|
||||
mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
|
||||
ib_umem_release(srq->umem);
|
||||
}
|
||||
|
||||
|
||||
static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq)
|
||||
{
|
||||
kfree(srq->wrid);
|
||||
mlx5_buf_free(&dev->mdev, &srq->buf);
|
||||
mlx5_db_free(&dev->mdev, &srq->db);
|
||||
}
|
||||
|
||||
struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
|
||||
struct ib_srq_init_attr *init_attr,
|
||||
struct ib_udata *udata)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(pd->device);
|
||||
struct mlx5_ib_srq *srq;
|
||||
int desc_size;
|
||||
int buf_size;
|
||||
int err;
|
||||
struct mlx5_create_srq_mbox_in *uninitialized_var(in);
|
||||
int uninitialized_var(inlen);
|
||||
int is_xrc;
|
||||
u32 flgs, xrcdn;
|
||||
|
||||
/* Sanity check SRQ size before proceeding */
|
||||
if (init_attr->attr.max_wr >= dev->mdev.caps.max_srq_wqes) {
|
||||
mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
|
||||
init_attr->attr.max_wr,
|
||||
dev->mdev.caps.max_srq_wqes);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
srq = kmalloc(sizeof(*srq), GFP_KERNEL);
|
||||
if (!srq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mutex_init(&srq->mutex);
|
||||
spin_lock_init(&srq->lock);
|
||||
srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1);
|
||||
srq->msrq.max_gs = init_attr->attr.max_sge;
|
||||
|
||||
desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
|
||||
srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
|
||||
desc_size = roundup_pow_of_two(desc_size);
|
||||
desc_size = max_t(int, 32, desc_size);
|
||||
srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
|
||||
sizeof(struct mlx5_wqe_data_seg);
|
||||
srq->msrq.wqe_shift = ilog2(desc_size);
|
||||
buf_size = srq->msrq.max * desc_size;
|
||||
mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n",
|
||||
desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
|
||||
srq->msrq.max_avail_gather);
|
||||
|
||||
if (pd->uobject)
|
||||
err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen);
|
||||
else
|
||||
err = create_srq_kernel(dev, srq, &in, buf_size, &inlen);
|
||||
|
||||
if (err) {
|
||||
mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
|
||||
pd->uobject ? "user" : "kernel", err);
|
||||
goto err_srq;
|
||||
}
|
||||
|
||||
is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
|
||||
in->ctx.state_log_sz = ilog2(srq->msrq.max);
|
||||
flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24;
|
||||
xrcdn = 0;
|
||||
if (is_xrc) {
|
||||
xrcdn = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
|
||||
in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(init_attr->ext.xrc.cq)->mcq.cqn);
|
||||
} else if (init_attr->srq_type == IB_SRQT_BASIC) {
|
||||
xrcdn = to_mxrcd(dev->devr.x0)->xrcdn;
|
||||
in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(dev->devr.c0)->mcq.cqn);
|
||||
}
|
||||
|
||||
in->ctx.flags_xrcd = cpu_to_be32((flgs & 0xFF000000) | (xrcdn & 0xFFFFFF));
|
||||
|
||||
in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn);
|
||||
in->ctx.db_record = cpu_to_be64(srq->db.dma);
|
||||
err = mlx5_core_create_srq(&dev->mdev, &srq->msrq, in, inlen);
|
||||
mlx5_vfree(in);
|
||||
if (err) {
|
||||
mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
|
||||
goto err_srq;
|
||||
}
|
||||
|
||||
mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
|
||||
|
||||
srq->msrq.event = mlx5_ib_srq_event;
|
||||
srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
|
||||
|
||||
if (pd->uobject)
|
||||
if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
|
||||
mlx5_ib_dbg(dev, "copy to user failed\n");
|
||||
err = -EFAULT;
|
||||
goto err_core;
|
||||
}
|
||||
|
||||
init_attr->attr.max_wr = srq->msrq.max - 1;
|
||||
|
||||
return &srq->ibsrq;
|
||||
|
||||
err_core:
|
||||
mlx5_core_destroy_srq(&dev->mdev, &srq->msrq);
|
||||
if (pd->uobject)
|
||||
destroy_srq_user(pd, srq);
|
||||
else
|
||||
destroy_srq_kernel(dev, srq);
|
||||
|
||||
err_srq:
|
||||
kfree(srq);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
|
||||
enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
|
||||
struct mlx5_ib_srq *srq = to_msrq(ibsrq);
|
||||
int ret;
|
||||
|
||||
/* We don't support resizing SRQs yet */
|
||||
if (attr_mask & IB_SRQ_MAX_WR)
|
||||
return -EINVAL;
|
||||
|
||||
if (attr_mask & IB_SRQ_LIMIT) {
|
||||
if (attr->srq_limit >= srq->msrq.max)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&srq->mutex);
|
||||
ret = mlx5_core_arm_srq(&dev->mdev, &srq->msrq, attr->srq_limit, 1);
|
||||
mutex_unlock(&srq->mutex);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
|
||||
struct mlx5_ib_srq *srq = to_msrq(ibsrq);
|
||||
int ret;
|
||||
struct mlx5_query_srq_mbox_out *out;
|
||||
|
||||
out = kzalloc(sizeof(*out), GFP_KERNEL);
|
||||
if (!out)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mlx5_core_query_srq(&dev->mdev, &srq->msrq, out);
|
||||
if (ret)
|
||||
goto out_box;
|
||||
|
||||
srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm);
|
||||
srq_attr->max_wr = srq->msrq.max - 1;
|
||||
srq_attr->max_sge = srq->msrq.max_gs;
|
||||
|
||||
out_box:
|
||||
kfree(out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mlx5_ib_destroy_srq(struct ib_srq *srq)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(srq->device);
|
||||
struct mlx5_ib_srq *msrq = to_msrq(srq);
|
||||
|
||||
mlx5_core_destroy_srq(&dev->mdev, &msrq->msrq);
|
||||
|
||||
if (srq->uobject) {
|
||||
mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
|
||||
ib_umem_release(msrq->umem);
|
||||
} else {
|
||||
kfree(msrq->wrid);
|
||||
mlx5_buf_free(&dev->mdev, &msrq->buf);
|
||||
mlx5_db_free(&dev->mdev, &msrq->db);
|
||||
}
|
||||
|
||||
kfree(srq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index)
|
||||
{
|
||||
struct mlx5_wqe_srq_next_seg *next;
|
||||
|
||||
/* always called with interrupts disabled. */
|
||||
spin_lock(&srq->lock);
|
||||
|
||||
next = get_wqe(srq, srq->tail);
|
||||
next->next_wqe_index = cpu_to_be16(wqe_index);
|
||||
srq->tail = wqe_index;
|
||||
|
||||
spin_unlock(&srq->lock);
|
||||
}
|
||||
|
||||
int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
|
||||
struct ib_recv_wr **bad_wr)
|
||||
{
|
||||
struct mlx5_ib_srq *srq = to_msrq(ibsrq);
|
||||
struct mlx5_wqe_srq_next_seg *next;
|
||||
struct mlx5_wqe_data_seg *scat;
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
int nreq;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&srq->lock, flags);
|
||||
|
||||
for (nreq = 0; wr; nreq++, wr = wr->next) {
|
||||
if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
|
||||
err = -EINVAL;
|
||||
*bad_wr = wr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(srq->head == srq->tail)) {
|
||||
err = -ENOMEM;
|
||||
*bad_wr = wr;
|
||||
break;
|
||||
}
|
||||
|
||||
srq->wrid[srq->head] = wr->wr_id;
|
||||
|
||||
next = get_wqe(srq, srq->head);
|
||||
srq->head = be16_to_cpu(next->next_wqe_index);
|
||||
scat = (struct mlx5_wqe_data_seg *)(next + 1);
|
||||
|
||||
for (i = 0; i < wr->num_sge; i++) {
|
||||
scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
|
||||
scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey);
|
||||
scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
|
||||
}
|
||||
|
||||
if (i < srq->msrq.max_avail_gather) {
|
||||
scat[i].byte_count = 0;
|
||||
scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
|
||||
scat[i].addr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(nreq)) {
|
||||
srq->wqe_ctr += nreq;
|
||||
|
||||
/* Make sure that descriptors are written before
|
||||
* doorbell record.
|
||||
*/
|
||||
wmb();
|
||||
|
||||
*srq->db.db = cpu_to_be32(srq->wqe_ctr);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&srq->lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
121
drivers/infiniband/hw/mlx5/user.h
Normal file
121
drivers/infiniband/hw/mlx5/user.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Mellanox Technologies 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 MLX5_IB_USER_H
|
||||
#define MLX5_IB_USER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
MLX5_QP_FLAG_SIGNATURE = 1 << 0,
|
||||
MLX5_QP_FLAG_SCATTER_CQE = 1 << 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_SRQ_FLAG_SIGNATURE = 1 << 0,
|
||||
};
|
||||
|
||||
|
||||
/* Increment this value if any changes that break userspace ABI
|
||||
* compatibility are made.
|
||||
*/
|
||||
#define MLX5_IB_UVERBS_ABI_VERSION 1
|
||||
|
||||
/* Make sure that all structs defined in this file remain laid out so
|
||||
* that they pack the same way on 32-bit and 64-bit architectures (to
|
||||
* avoid incompatibility between 32-bit userspace and 64-bit kernels).
|
||||
* In particular do not use pointer types -- pass pointers in __u64
|
||||
* instead.
|
||||
*/
|
||||
|
||||
struct mlx5_ib_alloc_ucontext_req {
|
||||
__u32 total_num_uuars;
|
||||
__u32 num_low_latency_uuars;
|
||||
};
|
||||
|
||||
struct mlx5_ib_alloc_ucontext_resp {
|
||||
__u32 qp_tab_size;
|
||||
__u32 bf_reg_size;
|
||||
__u32 tot_uuars;
|
||||
__u32 cache_line_size;
|
||||
__u16 max_sq_desc_sz;
|
||||
__u16 max_rq_desc_sz;
|
||||
__u32 max_send_wqebb;
|
||||
__u32 max_recv_wr;
|
||||
__u32 max_srq_recv_wr;
|
||||
__u16 num_ports;
|
||||
__u16 reserved;
|
||||
};
|
||||
|
||||
struct mlx5_ib_alloc_pd_resp {
|
||||
__u32 pdn;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_cq {
|
||||
__u64 buf_addr;
|
||||
__u64 db_addr;
|
||||
__u32 cqe_size;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_cq_resp {
|
||||
__u32 cqn;
|
||||
__u32 reserved;
|
||||
};
|
||||
|
||||
struct mlx5_ib_resize_cq {
|
||||
__u64 buf_addr;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_srq {
|
||||
__u64 buf_addr;
|
||||
__u64 db_addr;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_srq_resp {
|
||||
__u32 srqn;
|
||||
__u32 reserved;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_qp {
|
||||
__u64 buf_addr;
|
||||
__u64 db_addr;
|
||||
__u32 sq_wqe_count;
|
||||
__u32 rq_wqe_count;
|
||||
__u32 rq_wqe_shift;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct mlx5_ib_create_qp_resp {
|
||||
__u32 uuar_index;
|
||||
};
|
||||
#endif /* MLX5_IB_USER_H */
|
||||
@@ -19,5 +19,6 @@ config NET_VENDOR_MELLANOX
|
||||
if NET_VENDOR_MELLANOX
|
||||
|
||||
source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
|
||||
source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_MELLANOX
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MLX4_CORE) += mlx4/
|
||||
obj-$(CONFIG_MLX5_CORE) += mlx5/core/
|
||||
|
||||
18
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
Normal file
18
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Mellanox driver configuration
|
||||
#
|
||||
|
||||
config MLX5_CORE
|
||||
tristate
|
||||
depends on PCI && X86
|
||||
default n
|
||||
|
||||
config MLX5_DEBUG
|
||||
bool "Verbose debugging output" if (MLX5_CORE && EXPERT)
|
||||
depends on MLX5_CORE
|
||||
default y
|
||||
---help---
|
||||
This option causes debugging code to be compiled into the
|
||||
mlx5_core driver. The output can be turned on via the
|
||||
debug_mask module parameter (which can also be set after
|
||||
the driver is loaded through sysfs).
|
||||
5
drivers/net/ethernet/mellanox/mlx5/core/Makefile
Normal file
5
drivers/net/ethernet/mellanox/mlx5/core/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
|
||||
|
||||
mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
|
||||
health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
|
||||
mad.o
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user