--- /dev/null
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Wei Lin Guay <wei.lin.guay@oracle.com>
+ *
+ * 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 <rdma/ib_verbs.h>
+#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
+
--- /dev/null
+/*
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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
--- /dev/null
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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 <linux/module.h>
+#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);
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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 <rdma/ib_verbs.h>
+#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
--- /dev/null
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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 <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/highmem.h>
+#include <linux/kgdb.h>
+
+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);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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 <linux/idr.h>
+#include <rdma/ib_verbs.h>
+#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;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Author: Knut Omang <knut.omang@oracle.com>
+ *
+ * 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 */