From 72c2d6e82603da8fa2ab5ee6704126517321ad79 Mon Sep 17 00:00:00 2001 From: Wei Lin Guay Date: Tue, 24 May 2016 09:37:22 +0200 Subject: [PATCH] sif driver initial commit part 4 sif_tqp.h: Implementation of EPSA tunnelling QP for SIF sif_user.h: This file defines sif specific verbs extension request/response. sif_verbs.c: IB verbs API extensions specific to PSIF sif_verbs.h: IB verbs API extensions specific to PSIF sif_vf.c: SR/IOV support functions sif_vf.h: SR/IOV support functions sif_xmmu.c: Implementation of special MMU mappings. sif_xmmu.h: Implementation of special MMU mappings. sif_xrc.c: Implementation of XRC related functions sif_xrc.h: XRC related functions version.h: Detailed version info data structure Signed-off-by: Knut Omang --- drivers/infiniband/hw/sif/sif_tqp.h | 43 +++++ drivers/infiniband/hw/sif/sif_user.h | 222 ++++++++++++++++++++++++++ drivers/infiniband/hw/sif/sif_verbs.c | 74 +++++++++ drivers/infiniband/hw/sif/sif_verbs.h | 114 +++++++++++++ drivers/infiniband/hw/sif/sif_vf.c | 67 ++++++++ drivers/infiniband/hw/sif/sif_vf.h | 19 +++ drivers/infiniband/hw/sif/sif_xmmu.c | 98 ++++++++++++ drivers/infiniband/hw/sif/sif_xmmu.h | 29 ++++ drivers/infiniband/hw/sif/sif_xrc.c | 83 ++++++++++ drivers/infiniband/hw/sif/sif_xrc.h | 39 +++++ drivers/infiniband/hw/sif/version.h | 29 ++++ 11 files changed, 817 insertions(+) create mode 100644 drivers/infiniband/hw/sif/sif_tqp.h create mode 100644 drivers/infiniband/hw/sif/sif_user.h create mode 100644 drivers/infiniband/hw/sif/sif_verbs.c create mode 100644 drivers/infiniband/hw/sif/sif_verbs.h create mode 100644 drivers/infiniband/hw/sif/sif_vf.c create mode 100644 drivers/infiniband/hw/sif/sif_vf.h create mode 100644 drivers/infiniband/hw/sif/sif_xmmu.c create mode 100644 drivers/infiniband/hw/sif/sif_xmmu.h create mode 100644 drivers/infiniband/hw/sif/sif_xrc.c create mode 100644 drivers/infiniband/hw/sif/sif_xrc.h create mode 100644 drivers/infiniband/hw/sif/version.h diff --git a/drivers/infiniband/hw/sif/sif_tqp.h b/drivers/infiniband/hw/sif/sif_tqp.h new file mode 100644 index 000000000000..857d45a99a84 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_tqp.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Wei Lin Guay + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_tqp.h: Implementation of EPSA tunnelling QP for SIF + */ + +#ifndef __SIF_TQP_H +#define __SIF_TQP_H +#include +#include "sif_dev.h" +#include "sif_base.h" +#include "sif_epsc.h" +#include "sif_cq.h" + +static inline enum psif_mbox_type u32_to_mbox(u32 proxy) +{ + switch (proxy) { + case 0: + return MBOX_EPSA0; + case 1: + return MBOX_EPSA1; + case 2: + return MBOX_EPSA2; + case 3: + return MBOX_EPSA3; + default: + break; + } + return (enum psif_mbox_type) -1; +} + +extern int sif_epsa_tunneling_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); + +#endif + diff --git a/drivers/infiniband/hw/sif/sif_user.h b/drivers/infiniband/hw/sif/sif_user.h new file mode 100644 index 000000000000..b46211bc608b --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_user.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_user.h: This file defines sif specific verbs extension request/response. + */ + +#ifndef _SIF_USER_H +#define _SIF_USER_H + +/* Binary interface control: + * Major version difference indicate backward incompatible changes + * Minor version difference indicate that only a common subset of + * features are available. + * + */ +#define SIF_UVERBS_ABI_MAJOR_VERSION 3 +#define SIF_UVERBS_ABI_MINOR_VERSION 4 + +#define SIF_UVERBS_VERSION(x, y) ((x) << 8 | (y)) + +#define SIF_UVERBS_ABI_VERSION \ + SIF_UVERBS_VERSION(SIF_UVERBS_ABI_MAJOR_VERSION, SIF_UVERBS_ABI_MINOR_VERSION) + +/* + * Bit 5 is not used by the PSIF_WC_OPCODE_FOO_BAR enums. Hence, using + * it to indicate if QP has been destroyed before the CQE has been + * polled + */ +#define SIF_WC_QP_DESTROYED (1<<5) + +/* + * This struct will be amended to an un-polled cqe, in case the QP has + * been destroyed before the CQEs are polled. The information is + * needed in order to handle flushing of SRQs and generation of Last + * WQE Reached event. + * + * The information amended to the CQE is _only_ valid if the CQE has + * been marked with SIF_WC_QP_DESTROYED. + */ +struct sif_post_mortem_qp_info_in_cqe { + bool was_srq; + int srq_idx; + int qpn; /* Could be useful for de-bugging/logging */ +}; + + +#ifndef _SIF_H +/* These definitions must be kept in sync with + * the ones in libsif's sif.h + */ +enum sif_vendor_flags { + MMU_special = 0x1, /* Use special mmu setup in associated mappings + * NB! Modifies input to ibv_reg_mr! + */ + SQ_mode = 0x2, /* Trigger send queue mode instead of using VCBs */ + proxy_mode = 0x4, /* Enable EPS-A proxying - requires the eps_a field to be set */ + SVF_kernel_mode = 0x8, /* Enable kernel mode - default is direct user mode */ + tsu_qosl = 0x10, /* Value to use for the qosl bit in the qp state */ + no_checksum = 0x20, /* No csum for qp, wqe.wr.csum = qp.magic */ + dynamic_mtu = 0x40, /* dynamic MTU - use 256B instead of the path MTU */ +}; + +enum sif_mem_type { + SIFMT_BYPASS, /* Use MMU bypass in associated mmu contexts */ + SIFMT_UMEM, /* Normal default umem based user level mapping */ + SIFMT_UMEM_SPT, /* Mapping of user memory based on the process' own page table */ + SIFMT_CS, /* A large (sparsely populated) SIF only vaddr mapping (used for SQ CMPL) */ + SIFMT_ZERO, /* Special mapping of a vaddr range to a single page (see #1931) */ + SIFMT_BYPASS_RO, /* MMU bypass mapped read only for device (requires IOMMU enabled) */ + SIFMT_UMEM_RO, /* GVA2GPA mapped read only for device (requires IOMMU enabled) */ + SIFMT_PHYS, /* Use GVA2GPA but input is based on a phys_buf array instead of umem */ + SIFMT_FMR, /* Use GVA2GPA but input is based on a page address array instead of umem */ + SIFMT_2M, /* sif_kmem based 2M page allocation */ + SIFMT_NOMEM, /* Bypass mode - special kernel mappings with no memory allocated */ + SIFMT_4K, /* sif_kmem based 4K page allocation */ + SIFMT_PTONLY, /* No memory allocated but full page table needed (FMR init) */ + SIFMT_MAX +}; + +enum sif_proxy_type { + SIFPX_OFF, /* Default value - no proxying */ + SIFPX_EPSA_1, + SIFPX_EPSA_2, + SIFPX_EPSA_3, + SIFPX_EPSA_4 +}; + +enum sif_flush_type { + NO_FLUSH, + FLUSH_SQ, + FLUSH_RQ +}; +#endif + +/* These should be multiple of 64 bytes and densely packed: */ + +struct sif_get_context_ext { + __u32 abi_version; /* Let the driver know which version we are */ + __u32 reserved; +}; + +struct sif_get_context_resp_ext { + __u32 sq_sw_ext_sz; /* Distance in bytes between descriptor elements */ + __u32 rq_ext_sz; + __u32 cq_ext_sz; + __u32 sq_entry_per_block; /* Number of entries per block of descriptors */ + __u32 rq_entry_per_block; + __u32 cq_entry_per_block; + __u32 sq_hw_ext_sz; /* Dist between sq hw descriptor elms, from >= v.3.3 */ + __u32 reserved; +}; + +struct sif_alloc_pd_resp_ext { + __u32 cb_idx; /* The virtual collect buffer to use by this protection domain */ + __u32 reserved; +}; + +/* TBD: We must filter this structure before we go upstream */ +struct sif_share_pd_resp_ext { + __u32 cb_idx; /* The virtual collect buffer to use by this shared protection domain */ + __u32 reserved; +}; + +struct sif_create_cq_ext { + enum sif_vendor_flags flags; + enum sif_proxy_type proxy; +}; + +struct sif_create_cq_resp_ext { + __u32 cq_idx; + __u32 reserved; +}; + +struct sif_create_qp_ext { + enum sif_vendor_flags flags; + enum sif_proxy_type proxy; +}; + +struct sif_create_qp_resp_ext { + __u32 qp_idx; + __u32 rq_idx; + __u32 magic; + __u32 sq_extent; + __u32 rq_extent; + __u32 sq_sgl_offset; + __u32 sq_mr_idx; + __u32 reserved; + __u64 sq_dma_handle; +}; + +struct sif_modify_qp_ext { + enum sif_flush_type flush; + __u32 reserved; +}; + +struct sif_reg_mr_ext { + enum sif_vendor_flags flags; + enum sif_mem_type mem_type; + __u64 map_length; /* Used by gva_type SIFGT_ZERO - indicates psif vmap length */ + __u64 phys_length; /* Used by gva_type SIFGT_ZERO - indicates valid memory length */ +}; + +struct sif_reg_mr_resp_ext { + __u64 uv2dma; /* Used to support bypass mode */ +}; + +struct sif_create_srq_ext { + enum sif_vendor_flags flags; + __u32 res1; +}; + +struct sif_create_srq_resp_ext { + __u32 index; + __u32 extent; +}; + +struct sif_create_ah_resp_ext { + __u32 index; + __u32 reserved; +}; + +/* mmap offset encoding */ + +enum sif_mmap_cmd { + SIF_MAP_NONE, /* No mapping */ + SIF_MAP_CB, /* Map a collect buffer - cb index as argument */ + SIF_MAP_SQ, /* Map an SQ,RQ or CQ (entries) - queue index as argument */ + SIF_MAP_RQ, + SIF_MAP_CQ, + SIF_MAP_SQ_SW, /* Map a block of SQ,RQ or CQ software descriptors - block index as argument */ + SIF_MAP_RQ_SW, + SIF_MAP_CQ_SW, + /* These are safe to map read-only (so far only sq_hw in use) */ + SIF_MAP_QP, /* Map a block of qp descriptors - block index as argument */ + SIF_MAP_SQ_HW, /* Map a block of SQ,RQ or CQ hardware descriptors - block index as argument */ + SIF_MAP_RQ_HW, + SIF_MAP_CQ_HW, + SIF_MAP_MAX +}; + + +#define SIF_MCMD_SHIFT (PAGE_SHIFT + 32) + +static inline __u64 mmap_set_cmd(enum sif_mmap_cmd cmd, __u32 index) +{ + return ((__u64)cmd << SIF_MCMD_SHIFT) | ((__u64)index << PAGE_SHIFT); +} + +static inline void mmap_get_cmd(__u64 offset, enum sif_mmap_cmd *cmdp, __u32 *idxp) +{ + *cmdp = (enum sif_mmap_cmd)((offset >> SIF_MCMD_SHIFT) & 0xff); + *idxp = (offset >> PAGE_SHIFT) & 0xffffffff; +} + +#endif diff --git a/drivers/infiniband/hw/sif/sif_verbs.c b/drivers/infiniband/hw/sif/sif_verbs.c new file mode 100644 index 000000000000..0525ccc42dff --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_verbs.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_verbs.c: IB verbs API extensions specific to PSIF + */ + +#include +#include "sif_verbs.h" +#include "sif_dev.h" +#include "sif_epsc.h" +#include "psif_hw_data.h" +#include "psif_hw_csr.h" + +/* Set/get the 48 bit ethernet mac address for a port */ +int sif_get_mac(struct ib_device *dev, u8 port, u16 uf, u64 *address) +{ + int ret = 0; + struct sif_dev *sdev = to_sdev(dev); + struct psif_epsc_csr_rsp cqe; + struct psif_epsc_csr_req req; + + if (port > 2) + return -ENODEV; + + memset(&req, 0, sizeof(req)); + + req.opcode = EPSC_QUERY; + req.uf = uf; + req.u.query.info.op = EPSC_QUERY_VPD_MAC; + req.u.query.info.index = port; + req.u.query.data.op = EPSC_QUERY_BLANK; /* Single query */ + + ret = sif_epsc_wr(sdev, &req, &cqe); + if (ret) { + *address = 0; + sif_log(sdev, SIF_INFO, "Failed with status %d", ret); + } else { + *address = cqe.info; + } + return ret; +} +EXPORT_SYMBOL(sif_get_mac); + +int sif_set_mac(struct ib_device *dev, u8 port, u16 uf, u64 address) +{ + int ret = 0; + struct sif_dev *sdev = to_sdev(dev); + struct psif_epsc_csr_rsp cqe; + struct psif_epsc_csr_req req; + + if (port > 2) + return -ENODEV; + + memset(&req, 0, sizeof(req)); + + req.opcode = EPSC_SET_EOIB_MAC; + req.uf = uf; + req.u.set_eoib_mac.port = port; + req.u.set_eoib_mac.mac = address; + req.u.set_eoib_mac.index = 1; /* */ + + ret = sif_epsc_wr(sdev, &req, &cqe); + if (ret) + sif_log(sdev, SIF_INFO, "Failed with status %d", ret); + return ret; +} +EXPORT_SYMBOL(sif_set_mac); diff --git a/drivers/infiniband/hw/sif/sif_verbs.h b/drivers/infiniband/hw/sif/sif_verbs.h new file mode 100644 index 000000000000..1614e6a95ea1 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_verbs.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_verbs.h: IB verbs API extensions specific to PSIF + */ + +#ifndef _SIF_VERBS_H +#define _SIF_VERBS_H +#include +#include "sif_user.h" + +/*** sif verbs extensions ***/ + +enum sif_eoib_ctrl { + /* Per UF controls */ + SIF_EC_UPM = 1 << 0, /* Unicast promiscuous mode */ + SIF_EC_MPM = 1 << 1, /* Multicast promiscuous mode */ + SIF_EC_ABC = 1 << 2, /* Accept broadcast packets */ + SIF_EC_PAD = 1 << 3, /* Ethernet padding */ + /* HCA wide (PF only) controls */ + SIF_EC_UOFE = 1 << 10, /* Unicast overflow table enable */ + SIF_EC_RTP = 1 << 11, /* Receive tossed packets */ + SIF_EC_DVM = 1 << 12, /* Double VLAN mode */ + SIF_EC_VEM = 1 << 13, /* VLAN Enforcement mode */ + SIF_EC_NSM = 1 << 14, /* No strip mode */ +}; + + +/* If this bit is set in the device_modify_mask to ib_modify_device + * the sif ib driver will assume that the provided ib_device_attr + * is embedded in a sif_device_modify struct. + */ +enum sif_device_modify_flags { + IB_DEVICE_MODIFY_EXTENDED = 1 << 3 +}; + + +struct sif_device_modify { + struct ib_device_modify ib; + /* These two masks use values from sif_eoib_ctrl */ + u32 eoib_ctrl; /* Indicate affected bits in eoib_data */ + u32 eoib_data; /* Values to set/unset, only bits set in eoib_ctrl affected */ + u16 uf; /* This field is only valid from PF */ +}; + + +/* Extension bits in the qp create mask to ib_create_qp + */ +enum sif_qp_create_flags { + IB_QP_CREATE_EOIB = 1 << 4, /* Indicate that this is an Ethernet over IB QP */ + IB_QP_CREATE_RSS = 1 << 5, /* Enable receive side scaling */ + IB_QP_CREATE_HDR_SPLIT = 1 << 6, /* Enable header/data split for offloading */ + IB_QP_CREATE_RCV_DYNAMIC_MTU = 1 << 7, /* Enable receive side dynamic mtu */ + IB_QP_CREATE_PROXY = 1 << 8, /* Enable a special EPSA proxy */ + IB_QP_NO_CSUM = 1 << 9, /* No csum for qp, wqe.wr.csum = qp.magic */ + IB_QP_CREATE_SND_DYNAMIC_MTU = 1 << 10, /* Enable receive side dynamic mtu */ +}; + + +/* Extension bits in the qp attr mask to ib_modify_qp + * TBD: Not implemented yet + */ +enum sif_qp_attr_mask { + IB_QP_EOIB = 1 << 24, /* Enable as an Ethernet over IB QP */ + IB_QP_IPOIB = 1 << 25, /* Enable as an IP over IB QP */ + IB_QP_RSS = 1 << 26, /* Enable receive side scaling */ + IB_QP_HDR_SPLIT = 1 << 27, /* Enable header/data split for offloading */ + IB_QP_RCV_DYN_MTU = 1 << 28, /* Enable receive side dynamic mtu */ + IB_QP_SND_DYN_MTU = 1 << 29, /* Enable send side dynamic mtu */ +}; + + +/* Set/get the 48 bit ethernet mac address for a port on a uf + * The uf field is ignored for all ufs except uf 0 (PF) + */ +int sif_get_mac(struct ib_device *dev, u8 port, u16 uf, u64 *address); +int sif_set_mac(struct ib_device *dev, u8 port, u16 uf, u64 address); + +struct sif_dev; +struct psif_epsc_csr_req; +struct psif_epsc_csr_rsp; +enum psif_mbox_type; + +struct sif_verbs { + /* Exposed internal create_cq call to allow creation of proxy CQs. + * Needed by EPSA users. Implemented in sif_cq.c. + */ + struct ib_cq * (*create_cq)(struct ib_device *ibdev, int cqe, + int comp_vector, struct ib_ucontext *context, + struct ib_udata *udata, + enum sif_proxy_type proxy); + int (*eps_wr)(struct ib_device *ibdev, enum psif_mbox_type eps_num, + struct psif_epsc_csr_req *req, struct psif_epsc_csr_rsp *cqe); +}; + +/* TBD: External rep of struct sif_dev - must be kept synchronized */ +struct sif_device { + struct ib_device ib_dev; + struct sif_verbs sv; +}; + +static inline struct sif_device *to_sif_device(struct ib_device *ibdev) +{ + return container_of(ibdev, struct sif_device, ib_dev); +} + +#endif diff --git a/drivers/infiniband/hw/sif/sif_vf.c b/drivers/infiniband/hw/sif/sif_vf.c new file mode 100644 index 000000000000..a2cbcbea4f85 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_vf.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_vf.c: SR/IOV support functions + */ +#include "sif_dev.h" +#include "sif_vf.h" + +int sif_vf_enable(struct pci_dev *dev, int num_vfs) +{ + struct sif_dev *sdev = pci_get_drvdata(dev); + int ret = 0; + + if (sdev->is_vf) + return 0; + if (sdev->fw_vfs < 0) { + struct psif_epsc_csr_req req; + struct psif_epsc_csr_rsp rsp; + /* Ask the EPSC how many VFs that are enabled */ + memset(&req, 0, sizeof(req)); + req.opcode = EPSC_QUERY; + req.u.query.data.op = EPSC_QUERY_NUM_UF; + ret = sif_epsc_wr(sdev, &req, &rsp); + if (ret) { + sif_log(sdev, SIF_INFO, + "Request to the EPSC for number of VFs configured failed with %d", ret); + return ret; + } + sdev->fw_vfs = rsp.data - 1; + sif_log(sdev, SIF_INFO, "Firmware supports %d VFs", sdev->fw_vfs); + } + + if (num_vfs > sdev->fw_vfs) { + sif_log(sdev, SIF_INFO, "Requested %d vfs - limited by firmware to %d", + num_vfs, sdev->fw_vfs); + num_vfs = sdev->fw_vfs; + } + if (num_vfs) { + ret = pci_enable_sriov(dev, num_vfs); + if (ret < 0) { + sif_log(sdev, SIF_INFO, "Failed (status %d) to enable %d VFs", + ret, num_vfs); + goto sriov_failed; + } + sif_log(sdev, SIF_INFO, "Enabled %d VFs", num_vfs); + sdev->num_vfs = num_vfs; + } else + pci_disable_sriov(sdev->pdev); +sriov_failed: + return ret; +} + + +void sif_vf_disable(struct sif_dev *sdev) +{ + if (sdev->num_vfs) { + pci_disable_sriov(sdev->pdev); + sdev->num_vfs = 0; + } +} diff --git a/drivers/infiniband/hw/sif/sif_vf.h b/drivers/infiniband/hw/sif/sif_vf.h new file mode 100644 index 000000000000..5184a35c8097 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_vf.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_vf.h: SR/IOV support functions + */ +#ifndef __SIF_VF_H +#define __SIF_VF_H + +int sif_vf_enable(struct pci_dev *dev, int num_vfs); +void sif_vf_disable(struct sif_dev *sdev); + +#endif diff --git a/drivers/infiniband/hw/sif/sif_xmmu.c b/drivers/infiniband/hw/sif/sif_xmmu.c new file mode 100644 index 000000000000..7b69280c5ea6 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_xmmu.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_xmmu.c: Implementation of special MMU mappings. + */ + +#include "sif_mmu.h" +#include "sif_spt.h" +#include "sif_xmmu.h" +#include "sif_dev.h" +#include "sif_dma.h" +#include "sif_mem.h" +#include "sif_pt.h" +#include +#include +#include +#include + +int sif_zero_map_gva_ctx(struct sif_dev *sdev, + struct sif_mmu_ctx *ctx, + struct sif_mem *mem, + bool write) +{ + int i, ret; + u32 map_cnt; /* Number of overlapping maps of the same physical region */ + u64 phys_size = ctx->phys_sz = mem->size; /* Tyically smaller than ctx->size */ + u64 phys_pages; + u64 start = ctx->base; + struct sif_pt *pt; + struct psif_mmu_cntx *hw_ctx = &ctx->mctx; + struct scatterlist *sg = sif_mem_get_sgl(mem); + + if (!phys_size || phys_size & ~PAGE_MASK) { + sif_log(sdev, SIF_INFO, "Invalid phys_length specified (0x%llx)", phys_size); + return -EINVAL; + } + + map_cnt = ctx->size / phys_size; + phys_pages = phys_size >> sdev->mi.page_shift; + + if (phys_pages > sdev->mi.ptes_per_page) { + sif_log(sdev, SIF_INFO, + "Illegal phys_length specified (0x%llx) max %u pages supported", + phys_size, sdev->mi.ptes_per_page); + return -EINVAL; + } + if (map_cnt * phys_size != ctx->size) { + sif_log(sdev, SIF_INFO, + "Illegal virtual/phys length specified (0x%llx/0x%llx) must be a multiple", + ctx->size, phys_size); + return -EINVAL; + } + + pt = sif_pt_create_empty(sdev, start, mem->mem_type); + if (!pt) + return -ENOMEM; + + ctx->pt = pt; + hw_ctx->wr_access = write; + hw_ctx->translation_type = MMU_GVA2GPA_MODE; + hw_ctx->page_size = PAGE_SIZE_IA32E_4KB; + + for (i = 0; i < map_cnt; i++) { + ret = sif_pt_extend(pt, sg, start, phys_size); + if (ret < 0) + goto extend_failed; + start += phys_size; + } + return 0; + +extend_failed: + for (; i >= 0; i--) { + start -= phys_size; + sif_pt_free_part(pt, start, phys_size); + } + return ret; +} + +void sif_zero_unmap_gva_ctx(struct sif_dev *sdev, struct sif_mmu_ctx *ctx) +{ + int i; + u64 start = ctx->base; + u64 phys_size = ctx->phys_sz; + u32 map_cnt = ctx->size / phys_size; + + for (i = 0; i < map_cnt; i++) { + sif_pt_free_part(ctx->pt, start, phys_size); + start += phys_size; + } + sif_unmap_gva_ctx(sdev, ctx); +} diff --git a/drivers/infiniband/hw/sif/sif_xmmu.h b/drivers/infiniband/hw/sif/sif_xmmu.h new file mode 100644 index 000000000000..d45147b056a5 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_xmmu.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_xmmu.h: Implementation of special MMU mappings. + */ + +#ifndef _SIF_XMMU_H +#define _SIF_XMMU_H +struct sif_dev; +struct sif_mmu_ctx; + +/* Implementation of a mapping of a virtual address space onto a single page + * with minimal use of page table memory (workaround for #1931 + test support) + */ +int sif_zero_map_gva_ctx(struct sif_dev *sdev, + struct sif_mmu_ctx *ctx, + struct sif_mem *mem, + bool write); + +void sif_zero_unmap_gva_ctx(struct sif_dev *sdev, struct sif_mmu_ctx *ctx); + +#endif diff --git a/drivers/infiniband/hw/sif/sif_xrc.c b/drivers/infiniband/hw/sif/sif_xrc.c new file mode 100644 index 000000000000..134d714fe2ae --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_xrc.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_xrc.c: Implementation of XRC related functions + */ + +#include +#include +#include "sif_dev.h" +#include "sif_pd.h" +#include "sif_xrc.h" +#include "sif_idr.h" + + +int sif_init_xrcd(struct sif_dev *sdev) +{ + sif_idr_init(&sdev->xrcd_refs, 1, SIF_MAX_XRCD_INDEX); + return 0; +} + + +void sif_deinit_xrcd(struct sif_dev *sdev) +{ + /* Nothing to do yet */ +} + + +struct ib_xrcd *sif_alloc_xrcd(struct ib_device *device, + struct ib_ucontext *ucontext, + struct ib_udata *udata) +{ + struct sif_dev *sdev = to_sdev(device); + struct sif_xrcd *xrcd; + int ret = -ENOMEM; + + xrcd = kzalloc(sizeof(struct sif_xrcd), GFP_KERNEL); + if (!xrcd) + goto err_res_xrcd; + + ret = sif_idr_alloc(&sdev->xrcd_refs, xrcd, GFP_KERNEL); + if (ret < 0) { + sif_log(sdev, SIF_XRC, "idr_alloc failed with %d", ret); + goto err_idr_alloc; + } + xrcd->index = ret; + xrcd->pd = alloc_pd(sdev); + if (!xrcd->pd) { + ret = -ENOMEM; + sif_log(sdev, SIF_XRC, "alloc_pd failed with %d", ret); + goto err_alloc_pd; + } + xrcd->pd->ibpd.device = &sdev->ib_dev; + xrcd->pd->xrcd = xrcd; + sif_log(sdev, SIF_XRC, "index %d (pd %d)", xrcd->index, xrcd->pd->idx); + return &xrcd->ib_xrcd; + +err_alloc_pd: + sif_idr_remove(&sdev->xrcd_refs, xrcd->index); +err_idr_alloc: + kfree(xrcd); +err_res_xrcd: + return ERR_PTR(ret); +} + +int sif_dealloc_xrcd(struct ib_xrcd *ib_xrcd) +{ + struct sif_dev *sdev = to_sdev(ib_xrcd->device); + struct sif_xrcd *xrcd = to_sxrcd(ib_xrcd); + + sif_log(sdev, SIF_XRC, "index %d", xrcd->index); + + dealloc_pd(xrcd->pd); + sif_idr_remove(&sdev->xrcd_refs, xrcd->index); + kfree(xrcd); + return 0; +} diff --git a/drivers/infiniband/hw/sif/sif_xrc.h b/drivers/infiniband/hw/sif/sif_xrc.h new file mode 100644 index 000000000000..0a41bd1179f7 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_xrc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_xrc.h: XRC related functions + */ + +#ifndef __SIF_XRC_H +#define __SIF_XRC_H + +/* SIF supports a 24 bit XRCD domain index: */ +#define SIF_MAX_XRCD_INDEX ((1 << 24) - 1) + +struct sif_xrcd { + struct ib_xrcd ib_xrcd; + int index; + struct sif_pd *pd; +}; + +static inline struct sif_xrcd *to_sxrcd(struct ib_xrcd *ibxrcd) +{ + return container_of(ibxrcd, struct sif_xrcd, ib_xrcd); +} + +int sif_init_xrcd(struct sif_dev *sdev); +void sif_deinit_xrcd(struct sif_dev *sdev); + +struct ib_xrcd *sif_alloc_xrcd(struct ib_device *device, + struct ib_ucontext *ucontext, + struct ib_udata *udata); +int sif_dealloc_xrcd(struct ib_xrcd *xrcd); + +#endif diff --git a/drivers/infiniband/hw/sif/version.h b/drivers/infiniband/hw/sif/version.h new file mode 100644 index 000000000000..9e91c005fa31 --- /dev/null +++ b/drivers/infiniband/hw/sif/version.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Author: Knut Omang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * version.h: Detailed version info data structure + */ +#ifndef SIF_VERSION_H +#define SIF_VERSION_H + +struct sif_version { + const char *git_repo; + const char *last_commit; + const char *git_status; + const char *build_user; + const char *build_git_time; + const char *git_psifapi_repo; + const char *last_psifapi_commit; + const char *git_psifapi_status; +}; + +extern struct sif_version sif_version; + +#endif /* SIF_VERSION_H */ -- 2.50.1