Message ID | 20190411110157.14252-4-yuval.shaia@oracle.com (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Series | VirtIO RDMA | expand |
On 2019/4/11 19:01, Yuval Shaia wrote: > Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com> > --- > drivers/infiniband/Kconfig | 1 + > drivers/infiniband/hw/Makefile | 1 + > drivers/infiniband/hw/virtio/Kconfig | 6 + > drivers/infiniband/hw/virtio/Makefile | 4 + > drivers/infiniband/hw/virtio/virtio_rdma.h | 40 + > .../infiniband/hw/virtio/virtio_rdma_device.c | 59 ++ > .../infiniband/hw/virtio/virtio_rdma_device.h | 32 + > drivers/infiniband/hw/virtio/virtio_rdma_ib.c | 711 ++++++++++++++++++ > drivers/infiniband/hw/virtio/virtio_rdma_ib.h | 48 ++ > .../infiniband/hw/virtio/virtio_rdma_main.c | 149 ++++ > .../infiniband/hw/virtio/virtio_rdma_netdev.c | 44 ++ > .../infiniband/hw/virtio/virtio_rdma_netdev.h | 33 + > include/uapi/linux/virtio_ids.h | 1 + > 13 files changed, 1129 insertions(+) > create mode 100644 drivers/infiniband/hw/virtio/Kconfig > create mode 100644 drivers/infiniband/hw/virtio/Makefile > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma.h > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_device.c > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_device.h > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_ib.c > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_ib.h > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_main.c > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_netdev.c > create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_netdev.h > > diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig > index a1fb840de45d..218a47d4cecf 100644 > --- a/drivers/infiniband/Kconfig > +++ b/drivers/infiniband/Kconfig > @@ -107,6 +107,7 @@ source "drivers/infiniband/hw/hfi1/Kconfig" > source "drivers/infiniband/hw/qedr/Kconfig" > source "drivers/infiniband/sw/rdmavt/Kconfig" > source "drivers/infiniband/sw/rxe/Kconfig" > +source "drivers/infiniband/hw/virtio/Kconfig" > endif > > source "drivers/infiniband/ulp/ipoib/Kconfig" > diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile > index e4f31c1be8f7..10ffb2c421e4 100644 > --- a/drivers/infiniband/hw/Makefile > +++ b/drivers/infiniband/hw/Makefile > @@ -14,3 +14,4 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ > obj-$(CONFIG_INFINIBAND_HNS) += hns/ > obj-$(CONFIG_INFINIBAND_QEDR) += qedr/ > obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re/ > +obj-$(CONFIG_INFINIBAND_VIRTIO_RDMA) += virtio/ > diff --git a/drivers/infiniband/hw/virtio/Kconfig b/drivers/infiniband/hw/virtio/Kconfig > new file mode 100644 > index 000000000000..92e41691cf5d > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/Kconfig > @@ -0,0 +1,6 @@ > +config INFINIBAND_VIRTIO_RDMA > + tristate "VirtIO Paravirtualized RDMA Driver" > + depends on NETDEVICES && ETHERNET && PCI && INET > + ---help--- > + This driver provides low-level support for VirtIO Paravirtual > + RDMA adapter. > diff --git a/drivers/infiniband/hw/virtio/Makefile b/drivers/infiniband/hw/virtio/Makefile > new file mode 100644 > index 000000000000..fb637e467167 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/Makefile > @@ -0,0 +1,4 @@ > +obj-$(CONFIG_INFINIBAND_VIRTIO_RDMA) += virtio_rdma.o > + > +virtio_rdma-y := virtio_rdma_main.o virtio_rdma_device.o virtio_rdma_ib.o \ > + virtio_rdma_netdev.o > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma.h b/drivers/infiniband/hw/virtio/virtio_rdma.h > new file mode 100644 > index 000000000000..7896a2dfb812 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma.h > @@ -0,0 +1,40 @@ > +/* > + * Virtio RDMA device: Driver main data types > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef __VIRTIO_RDMA__ > +#define __VIRTIO_RDMA__ > + > +#include <linux/virtio.h> > +#include <rdma/ib_verbs.h> > + > +struct virtio_rdma_info { > + struct ib_device ib_dev; > + struct virtio_device *vdev; > + struct virtqueue *ctrl_vq; > + wait_queue_head_t acked; /* arm on send to host, release on recv */ > + struct net_device *netdev; > +}; > + > +static inline struct virtio_rdma_info *to_vdev(struct ib_device *ibdev) > +{ > + return container_of(ibdev, struct virtio_rdma_info, ib_dev); > +} > + > +#endif > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_device.c b/drivers/infiniband/hw/virtio/virtio_rdma_device.c > new file mode 100644 > index 000000000000..ae41e530644f > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_device.c > @@ -0,0 +1,59 @@ > +/* > + * Virtio RDMA device: Device related functions and data > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include <linux/virtio_config.h> > + > +#include "virtio_rdma.h" > + > +static void rdma_ctrl_ack(struct virtqueue *vq) > +{ > + struct virtio_rdma_info *dev = vq->vdev->priv; > + > + wake_up(&dev->acked); > + > + printk("%s\n", __func__); Cool:-) this line should be for debug? Zhu Yanjun > +} > + > +int init_device(struct virtio_rdma_info *dev) > +{ > +#define TMP_MAX_VQ 1 > + int rc; > + struct virtqueue *vqs[TMP_MAX_VQ]; > + vq_callback_t *cbs[TMP_MAX_VQ]; > + const char *names[TMP_MAX_VQ]; > + > + names[0] = "ctrl"; > + cbs[0] = rdma_ctrl_ack; > + cbs[0] = NULL; > + > + rc = virtio_find_vqs(dev->vdev, TMP_MAX_VQ, vqs, cbs, names, NULL); > + if (rc) > + return rc; > + > + dev->ctrl_vq = vqs[0]; > + > + return 0; > +} > + > +void fini_device(struct virtio_rdma_info *dev) > +{ > + dev->vdev->config->reset(dev->vdev); > + dev->vdev->config->del_vqs(dev->vdev); > +} > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_device.h b/drivers/infiniband/hw/virtio/virtio_rdma_device.h > new file mode 100644 > index 000000000000..d9b1240daf92 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_device.h > @@ -0,0 +1,32 @@ > +/* > + * Virtio RDMA device: Device related functions and data > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef __VIRTIO_RDMA_DEVICE__ > +#define __VIRTIO_RDMA_DEVICE__ > + > +#define VIRTIO_RDMA_BOARD_ID 1 > +#define VIRTIO_RDMA_HW_NAME "virtio-rdma" > +#define VIRTIO_RDMA_HW_REV 1 > +#define VIRTIO_RDMA_DRIVER_VER "1.0" > + > +int init_device(struct virtio_rdma_info *dev); > +void fini_device(struct virtio_rdma_info *dev); > + > +#endif > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_ib.c b/drivers/infiniband/hw/virtio/virtio_rdma_ib.c > new file mode 100644 > index 000000000000..02bf4a332611 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_ib.c > @@ -0,0 +1,711 @@ > +/* > + * Virtio RDMA device: IB related functions and data > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include <linux/scatterlist.h> > +#include <linux/virtio.h> > +#include <rdma/ib_mad.h> > + > +#include "virtio_rdma.h" > +#include "virtio_rdma_device.h" > +#include "virtio_rdma_ib.h" > + > +/* TODO: Move to uapi header file */ > + > +/* > + * Control virtqueue data structures > + * > + * The control virtqueue expects a header in the first sg entry > + * and an ack/status response in the last entry. Data for the > + * command goes in between. > + */ > + > +#define VIRTIO_RDMA_CTRL_OK 0 > +#define VIRTIO_RDMA_CTRL_ERR 1 > + > +struct control_buf { > + __u8 cmd; > + __u8 status; > +}; > + > +enum { > + VIRTIO_CMD_QUERY_DEVICE = 10, > + VIRTIO_CMD_QUERY_PORT, > + VIRTIO_CMD_CREATE_CQ, > + VIRTIO_CMD_DESTROY_CQ, > + VIRTIO_CMD_CREATE_PD, > + VIRTIO_CMD_DESTROY_PD, > + VIRTIO_CMD_GET_DMA_MR, > +}; > + > +struct cmd_query_port { > + __u8 port; > +}; > + > +struct cmd_create_cq { > + __u32 cqe; > +}; > + > +struct rsp_create_cq { > + __u32 cqn; > +}; > + > +struct cmd_destroy_cq { > + __u32 cqn; > +}; > + > +struct rsp_create_pd { > + __u32 pdn; > +}; > + > +struct cmd_destroy_pd { > + __u32 pdn; > +}; > + > +struct cmd_get_dma_mr { > + __u32 pdn; > + __u32 access_flags; > +}; > + > +struct rsp_get_dma_mr { > + __u32 mrn; > + __u32 lkey; > + __u32 rkey; > +}; > + > +/* TODO: Move to uapi header file */ > + > +struct virtio_rdma_ib_cq { > + struct ib_cq ibcq; > + u32 cq_handle; > +}; > + > +/* TODO: For the scope fof the RFC i'm utilizing ib*_*_attr structures */ > + > +static int virtio_rdma_exec_cmd(struct virtio_rdma_info *di, int cmd, > + struct scatterlist *in, struct scatterlist *out) > +{ > + struct scatterlist *sgs[4], hdr, status; > + struct control_buf *ctrl; > + unsigned tmp; > + int rc; > + > + ctrl = kmalloc(sizeof(*ctrl), GFP_ATOMIC); > + ctrl->cmd = cmd; > + ctrl->status = ~0; > + > + sg_init_one(&hdr, &ctrl->cmd, sizeof(ctrl->cmd)); > + sgs[0] = &hdr; > + sgs[1] = in; > + sgs[2] = out; > + sg_init_one(&status, &ctrl->status, sizeof(ctrl->status)); > + sgs[3] = &status; > + > + rc = virtqueue_add_sgs(di->ctrl_vq, sgs, 2, 2, di, GFP_ATOMIC); > + if (rc) > + goto out; > + > + if (unlikely(!virtqueue_kick(di->ctrl_vq))) { > + goto out_with_status; > + } > + > + /* Spin for a response, the kick causes an ioport write, trapping > + * into the hypervisor, so the request should be handled > + * immediately */ > + while (!virtqueue_get_buf(di->ctrl_vq, &tmp) && > + !virtqueue_is_broken(di->ctrl_vq)) > + cpu_relax(); > + > +out_with_status: > + printk("%s: cmd %d, status %d\n", __func__, ctrl->cmd, ctrl->status); > + rc = ctrl->status == VIRTIO_RDMA_CTRL_OK ? 0 : 1; > + > +out: > + kfree(ctrl); > + > + return rc; > +} > + > +static int virtio_rdma_port_immutable(struct ib_device *ibdev, u8 port_num, > + struct ib_port_immutable *immutable) > +{ > + struct ib_port_attr attr; > + int rc; > + > + rc = ib_query_port(ibdev, port_num, &attr); > + if (rc) > + return rc; > + > + immutable->core_cap_flags |= RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; > + immutable->pkey_tbl_len = attr.pkey_tbl_len; > + immutable->gid_tbl_len = attr.gid_tbl_len; > + immutable->max_mad_size = IB_MGMT_MAD_SIZE; > + > + return 0; > +} > + > +static int virtio_rdma_query_device(struct ib_device *ibdev, > + struct ib_device_attr *props, > + struct ib_udata *uhw) > +{ > + struct scatterlist data; > + int offs; > + int rc; > + > + if (uhw->inlen || uhw->outlen) > + return -EINVAL; > + > + /* We start with sys_image_guid because of inconsistency beween ib_ > + * and ibv_ */ > + offs = offsetof(struct ib_device_attr, sys_image_guid); > + sg_init_one(&data, (void *)props + offs, sizeof(*props) - offs); > + > + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_QUERY_DEVICE, NULL, > + &data); > + > + printk("%s: sys_image_guid 0x%llx\n", __func__, > + be64_to_cpu(props->sys_image_guid)); > + > + return rc; > +} > + > +static int virtio_rdma_query_port(struct ib_device *ibdev, u8 port, > + struct ib_port_attr *props) > +{ > + struct scatterlist in, out; > + struct cmd_query_port *cmd; > + int offs; > + int rc; > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) > + return -ENOMEM; > + > + /* We start with state because of inconsistency beween ib and ibv */ > + offs = offsetof(struct ib_port_attr, state); > + sg_init_one(&out, (void *)props + offs, sizeof(*props) - offs); > + > + cmd->port = port; > + sg_init_one(&in, cmd, sizeof(*cmd)); > + printk("%s: port %d\n", __func__, cmd->port); > + > + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_QUERY_PORT, &in, > + &out); > + > + printk("%s: gid_tbl_len %d\n", __func__, props->gid_tbl_len); > + > + kfree(cmd); > + > + return rc; > +} > + > +static struct net_device *virtio_rdma_get_netdev(struct ib_device *ibdev, > + u8 port_num) > +{ > + struct virtio_rdma_info *ri = to_vdev(ibdev); > + > + printk("%s:\n", __func__); > + > + return ri->netdev; > +} > + > +struct ib_cq *virtio_rdma_create_cq(struct ib_device *ibdev, > + const struct ib_cq_init_attr *attr, > + struct ib_ucontext *context, > + struct ib_udata *udata) > +{ > + struct scatterlist in, out; > + struct virtio_rdma_ib_cq *vcq; > + struct cmd_create_cq *cmd; > + struct rsp_create_cq *rsp; > + struct ib_cq *cq = NULL; > + int rc; > + > + /* TODO: Check MAX_CQ */ > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) > + return ERR_PTR(-ENOMEM); > + > + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); > + if (!rsp) { > + kfree(cmd); > + return ERR_PTR(-ENOMEM); > + } > + > + vcq = kzalloc(sizeof(*vcq), GFP_KERNEL); > + if (!vcq) > + goto out; > + > + cmd->cqe = attr->cqe; > + sg_init_one(&in, cmd, sizeof(*cmd)); > + printk("%s: cqe %d\n", __func__, cmd->cqe); > + > + sg_init_one(&out, rsp, sizeof(*rsp)); > + > + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_CREATE_CQ, &in, > + &out); > + if (rc) > + goto out_err; > + > + printk("%s: cqn 0x%x\n", __func__, rsp->cqn); > + vcq->cq_handle = rsp->cqn; > + vcq->ibcq.cqe = attr->cqe; > + cq = &vcq->ibcq; > + > + goto out; > + > +out_err: > + kfree(vcq); > + return ERR_PTR(rc); > + > +out: > + kfree(rsp); > + kfree(cmd); > + return cq; > +} > + > +int virtio_rdma_destroy_cq(struct ib_cq *cq) > +{ > + struct virtio_rdma_ib_cq *vcq; > + struct scatterlist in; > + struct cmd_destroy_cq *cmd; > + int rc; > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) > + return -ENOMEM; > + > + vcq = container_of(cq, struct virtio_rdma_ib_cq, ibcq); > + > + cmd->cqn = vcq->cq_handle; > + sg_init_one(&in, cmd, sizeof(*cmd)); > + > + rc = virtio_rdma_exec_cmd(to_vdev(cq->device), VIRTIO_CMD_DESTROY_CQ, > + &in, NULL); > + > + kfree(cmd); > + > + kfree(vcq); > + > + return rc; > +} > + > +int virtio_rdma_alloc_pd(struct ib_pd *ibpd, struct ib_ucontext *context, > + struct ib_udata *udata) > +{ > + struct virtio_rdma_pd *pd = to_vpd(ibpd); > + struct ib_device *ibdev = ibpd->device; > + struct rsp_create_pd *rsp; > + struct scatterlist out; > + int rc; > + > + /* TODO: Check MAX_PD */ > + > + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); > + if (!rsp) > + return -ENOMEM; > + > + sg_init_one(&out, rsp, sizeof(*rsp)); > + > + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_CREATE_PD, NULL, > + &out); > + if (rc) > + goto out; > + > + pd->pd_handle = rsp->pdn; > + > + printk("%s: pd_handle=%d\n", __func__, pd->pd_handle); > + > +out: > + kfree(rsp); > + > + printk("%s: rc=%d\n", __func__, rc); > + return rc; > +} > + > +void virtio_rdma_dealloc_pd(struct ib_pd *pd) > +{ > + struct virtio_rdma_pd *vpd = to_vpd(pd); > + struct ib_device *ibdev = pd->device; > + struct cmd_destroy_pd *cmd; > + struct scatterlist in; > + > + printk("%s:\n", __func__); > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) > + return; > + > + cmd->pdn = vpd->pd_handle; > + sg_init_one(&in, cmd, sizeof(*cmd)); > + > + virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_DESTROY_PD, &in, NULL); > + > + kfree(cmd); > +} > + > +struct ib_mr *virtio_rdma_get_dma_mr(struct ib_pd *pd, int acc) > + > +{ > + struct virtio_rdma_user_mr *mr; > + struct scatterlist in, out; > + struct cmd_get_dma_mr *cmd = NULL; > + struct rsp_get_dma_mr *rsp = NULL; > + int rc; > + > + mr = kzalloc(sizeof(*mr), GFP_KERNEL); > + if (!mr) > + return ERR_PTR(-ENOMEM); > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) { > + kfree(mr); > + return ERR_PTR(-ENOMEM); > + } > + > + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); > + if (!cmd) { > + kfree(mr); > + kfree(cmd); > + return ERR_PTR(-ENOMEM); > + } > + > + cmd->pdn = to_vpd(pd)->pd_handle; > + cmd->access_flags = acc; > + sg_init_one(&in, cmd, sizeof(*cmd)); > + > + sg_init_one(&out, rsp, sizeof(*rsp)); > + > + rc = virtio_rdma_exec_cmd(to_vdev(pd->device), VIRTIO_CMD_GET_DMA_MR, > + &in, &out); > + if (rc) { > + kfree(mr); > + kfree(cmd); > + return ERR_PTR(rc); > + } > + > + mr->mr_handle = rsp->mrn; > + mr->ibmr.lkey = rsp->lkey; > + mr->ibmr.rkey = rsp->rkey; > + > + printk("%s: mr_handle=0x%x\n", __func__, mr->mr_handle); > + > + kfree(cmd); > + kfree(rsp); > + > + return &mr->ibmr; > +} > + > +struct ib_qp *virtio_rdma_create_qp(struct ib_pd *pd, > + struct ib_qp_init_attr *init_attr, > + struct ib_udata *udata) > +{ > + /* struct pvrdma_dev *dev = to_vdev(pd->device); */ > + struct virtio_rdma_qp *qp; > + > + printk("%s:\n", __func__); > + > + qp = kzalloc(sizeof(*qp), GFP_KERNEL); > + if (!qp) > + return ERR_PTR(-ENOMEM); > + > + return &qp->ibqp; > +} > + > +int virtio_rdma_query_gid(struct ib_device *ibdev, u8 port, int index, > + union ib_gid *gid) > +{ > + memset(gid, 0, sizeof(union ib_gid)); > + > + printk("%s: port %d, index %d\n", __func__, port, index); > + > + return 0; > +} > + > +static int virtio_rdma_add_gid(const struct ib_gid_attr *attr, void **context) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +struct ib_mr *virtio_rdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, > + u32 max_num_sg) > +{ > + printk("%s: mr_type %d, max_num_sg %d\n", __func__, mr_type, > + max_num_sg); > + > + return NULL; > +} > + > +int virtio_rdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +struct ib_ah *virtio_rdma_create_ah(struct ib_pd *pd, > + struct rdma_ah_attr *ah_attr, u32 flags, > + struct ib_udata *udata) > +{ > + printk("%s:\n", __func__); > + > + return NULL; > +} > + > +void virtio_rdma_dealloc_ucontext(struct ib_ucontext *ibcontext) > + > +{ > +} > + > +static int virtio_rdma_del_gid(const struct ib_gid_attr *attr, void **context) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_dereg_mr(struct ib_mr *ibmr) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_destroy_ah(struct ib_ah *ah, u32 flags) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +struct virtio_rdma_cq { > + struct ib_cq ibcq; > +}; > + > +int virtio_rdma_destroy_qp(struct ib_qp *qp) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +static void virtio_rdma_get_fw_ver_str(struct ib_device *device, char *str) > +{ > + printk("%s:\n", __func__); > +} > + > +enum rdma_link_layer virtio_rdma_port_link_layer(struct ib_device *ibdev, > + u8 port) > +{ > + return IB_LINK_LAYER_ETHERNET; > +} > + > +int virtio_rdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, > + int sg_nents, unsigned int *sg_offset) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_modify_port(struct ib_device *ibdev, u8 port, int mask, > + struct ib_port_modify *props) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, > + int attr_mask, struct ib_udata *udata) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, > + const struct ib_recv_wr **bad_wr) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, > + const struct ib_send_wr **bad_wr) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, > + u16 *pkey) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +int virtio_rdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, > + int attr_mask, struct ib_qp_init_attr *init_attr) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +struct ib_mr *virtio_rdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, > + u64 virt_addr, int access_flags, > + struct ib_udata *udata) > +{ > + printk("%s:\n", __func__); > + > + return NULL; > +} > + > +int virtio_rdma_req_notify_cq(struct ib_cq *ibcq, > + enum ib_cq_notify_flags notify_flags) > +{ > + printk("%s:\n", __func__); > + > + return 0; > +} > + > +static const struct ib_device_ops virtio_rdma_dev_ops = { > + .get_port_immutable = virtio_rdma_port_immutable, > + .query_device = virtio_rdma_query_device, > + .query_port = virtio_rdma_query_port, > + .get_netdev = virtio_rdma_get_netdev, > + .create_cq = virtio_rdma_create_cq, > + .destroy_cq = virtio_rdma_destroy_cq, > + .alloc_pd = virtio_rdma_alloc_pd, > + .dealloc_pd = virtio_rdma_dealloc_pd, > + .get_dma_mr = virtio_rdma_get_dma_mr, > + .create_qp = virtio_rdma_create_qp, > + .query_gid = virtio_rdma_query_gid, > + .add_gid = virtio_rdma_add_gid, > + .alloc_mr = virtio_rdma_alloc_mr, > + .alloc_ucontext = virtio_rdma_alloc_ucontext, > + .create_ah = virtio_rdma_create_ah, > + .dealloc_ucontext = virtio_rdma_dealloc_ucontext, > + .del_gid = virtio_rdma_del_gid, > + .dereg_mr = virtio_rdma_dereg_mr, > + .destroy_ah = virtio_rdma_destroy_ah, > + .destroy_qp = virtio_rdma_destroy_qp, > + .get_dev_fw_str = virtio_rdma_get_fw_ver_str, > + .get_link_layer = virtio_rdma_port_link_layer, > + .get_port_immutable = virtio_rdma_port_immutable, > + .map_mr_sg = virtio_rdma_map_mr_sg, > + .mmap = virtio_rdma_mmap, > + .modify_port = virtio_rdma_modify_port, > + .modify_qp = virtio_rdma_modify_qp, > + .poll_cq = virtio_rdma_poll_cq, > + .post_recv = virtio_rdma_post_recv, > + .post_send = virtio_rdma_post_send, > + .query_device = virtio_rdma_query_device, > + .query_pkey = virtio_rdma_query_pkey, > + .query_port = virtio_rdma_query_port, > + .query_qp = virtio_rdma_query_qp, > + .reg_user_mr = virtio_rdma_reg_user_mr, > + .req_notify_cq = virtio_rdma_req_notify_cq, > + INIT_RDMA_OBJ_SIZE(ib_pd, virtio_rdma_pd, ibpd), > +}; > + > +static ssize_t hca_type_show(struct device *device, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%s-%s\n", VIRTIO_RDMA_HW_NAME, > + VIRTIO_RDMA_DRIVER_VER); > +} > +static DEVICE_ATTR_RO(hca_type); > + > +static ssize_t hw_rev_show(struct device *device, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%d\n", VIRTIO_RDMA_HW_REV); > +} > +static DEVICE_ATTR_RO(hw_rev); > + > +static ssize_t board_id_show(struct device *device, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%d\n", VIRTIO_RDMA_BOARD_ID); > +} > +static DEVICE_ATTR_RO(board_id); > + > +static struct attribute *virtio_rdmaa_class_attributes[] = { > + &dev_attr_hw_rev.attr, > + &dev_attr_hca_type.attr, > + &dev_attr_board_id.attr, > + NULL, > +}; > + > +static const struct attribute_group virtio_rdmaa_attr_group = { > + .attrs = virtio_rdmaa_class_attributes, > +}; > + > +int init_ib(struct virtio_rdma_info *ri) > +{ > + int rc; > + > + ri->ib_dev.owner = THIS_MODULE; > + ri->ib_dev.num_comp_vectors = 1; > + ri->ib_dev.dev.parent = &ri->vdev->dev; > + ri->ib_dev.node_type = RDMA_NODE_IB_CA; > + ri->ib_dev.phys_port_cnt = 1; > + ri->ib_dev.uverbs_cmd_mask = > + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | > + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | > + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | > + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | > + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | > + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD); > + > + rdma_set_device_sysfs_group(&ri->ib_dev, &virtio_rdmaa_attr_group); > + > + ib_set_device_ops(&ri->ib_dev, &virtio_rdma_dev_ops); > + > + rc = ib_register_device(&ri->ib_dev, "virtio_rdma%d"); > + > + return rc; > +} > + > +void fini_ib(struct virtio_rdma_info *ri) > +{ > + ib_unregister_device(&ri->ib_dev); > +} > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_ib.h b/drivers/infiniband/hw/virtio/virtio_rdma_ib.h > new file mode 100644 > index 000000000000..7b82a60581ff > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_ib.h > @@ -0,0 +1,48 @@ > +/* > + * Virtio RDMA device: IB related functions and data > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef __VIRTIO_RDMA_IB__ > +#define __VIRTIO_RDMA_IB__ > + > +#include <rdma/ib_verbs.h> > + > +struct virtio_rdma_pd { > + struct ib_pd ibpd; > + u32 pd_handle; > +}; > + > +struct virtio_rdma_user_mr { > + struct ib_mr ibmr; > + u32 mr_handle; > +}; > + > +struct virtio_rdma_qp { > + struct ib_qp ibqp; > +}; > + > +static inline struct virtio_rdma_pd *to_vpd(struct ib_pd *ibpd) > +{ > + return container_of(ibpd, struct virtio_rdma_pd, ibpd); > +} > + > +int init_ib(struct virtio_rdma_info *ri); > +void fini_ib(struct virtio_rdma_info *ri); > + > +#endif > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_main.c b/drivers/infiniband/hw/virtio/virtio_rdma_main.c > new file mode 100644 > index 000000000000..811533d63160 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_main.c > @@ -0,0 +1,149 @@ > +/* > + * Virtio RDMA device > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include <linux/err.h> > +#include <linux/scatterlist.h> > +#include <linux/spinlock.h> > +#include <linux/virtio.h> > +#include <linux/module.h> > +#include <uapi/linux/virtio_ids.h> > + > +#include "virtio_rdma.h" > +#include "virtio_rdma_device.h" > +#include "virtio_rdma_ib.h" > +#include "virtio_rdma_netdev.h" > + > +/* TODO: > + * - How to hook to unload driver, we need to undo all the stuff with did > + * for all the devices that probed > + * - > + */ > + > +static int virtio_rdma_probe(struct virtio_device *vdev) > +{ > + struct virtio_rdma_info *ri; > + int rc = -EIO; > + > + ri = ib_alloc_device(virtio_rdma_info, ib_dev); > + if (!ri) { > + pr_err("Fail to allocate IB device\n"); > + rc = -ENOMEM; > + goto out; > + } > + vdev->priv = ri; > + > + ri->vdev = vdev; > + > + rc = init_device(ri); > + if (rc) { > + pr_err("Fail to connect to device\n"); > + goto out_dealloc_ib_device; > + } > + > + rc = init_netdev(ri); > + if (rc) { > + pr_err("Fail to connect to NetDev layer\n"); > + goto out_fini_device; > + } > + > + rc = init_ib(ri); > + if (rc) { > + pr_err("Fail to connect to IB layer\n"); > + goto out_fini_netdev; > + } > + > + pr_info("VirtIO RDMA device %d probed\n", vdev->index); > + > + goto out; > + > +out_fini_netdev: > + fini_netdev(ri); > + > +out_fini_device: > + fini_device(ri); > + > +out_dealloc_ib_device: > + ib_dealloc_device(&ri->ib_dev); > + > + vdev->priv = NULL; > + > +out: > + return rc; > +} > + > +static void virtio_rdma_remove(struct virtio_device *vdev) > +{ > + struct virtio_rdma_info *ri = vdev->priv; > + > + if (!ri) > + return; > + > + vdev->priv = NULL; > + > + fini_ib(ri); > + > + fini_netdev(ri); > + > + fini_device(ri); > + > + ib_dealloc_device(&ri->ib_dev); > + > + pr_info("VirtIO RDMA device %d removed\n", vdev->index); > +} > + > +static struct virtio_device_id id_table[] = { > + { VIRTIO_ID_RDMA, VIRTIO_DEV_ANY_ID }, > + { 0 }, > +}; > + > +static struct virtio_driver virtio_rdma_driver = { > + .driver.name = KBUILD_MODNAME, > + .driver.owner = THIS_MODULE, > + .id_table = id_table, > + .probe = virtio_rdma_probe, > + .remove = virtio_rdma_remove, > +}; > + > +static int __init virtio_rdma_init(void) > +{ > + int rc; > + > + rc = register_virtio_driver(&virtio_rdma_driver); > + if (rc) { > + pr_err("%s: Fail to register virtio driver (%d)\n", __func__, > + rc); > + return rc; > + } > + > + return 0; > +} > + > +static void __exit virtio_rdma_fini(void) > +{ > + unregister_virtio_driver(&virtio_rdma_driver); > +} > + > +module_init(virtio_rdma_init); > +module_exit(virtio_rdma_fini); > + > +MODULE_DEVICE_TABLE(virtio, id_table); > +MODULE_AUTHOR("Yuval Shaia"); > +MODULE_DESCRIPTION("Virtio RDMA driver"); > +MODULE_LICENSE("Dual BSD/GPL"); > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c > new file mode 100644 > index 000000000000..001f30b3e0b9 > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c > @@ -0,0 +1,44 @@ > +/* > + * Virtio RDMA device > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include "virtio_rdma_netdev.h" > + > +int init_netdev(struct virtio_rdma_info *ri) > +{ > + struct net_device *dev; > + struct virtio_rdma_netdev_info *vrndi; > + > + dev = alloc_etherdev(sizeof(struct virtio_rdma_netdev_info)); > + if (!dev) { > + return -ENOMEM; > + } > + > + SET_NETDEV_DEV(dev, &ri->vdev->dev); > + vrndi = netdev_priv(dev); > + vrndi->ri = ri; > + ri->netdev = dev; > + > + return 0; > +} > + > +void fini_netdev(struct virtio_rdma_info *ri) > +{ > + unregister_netdev(ri->netdev); > +} > diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h > new file mode 100644 > index 000000000000..e7e5d276d8ec > --- /dev/null > +++ b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h > @@ -0,0 +1,33 @@ > +/* > + * Virtio RDMA device: Netdev related functions and data > + * > + * Copyright (C) 2019 Yuval Shaia Oracle Corporation > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef __VIRTIO_RDMA_NETDEV__ > +#define __VIRTIO_RDMA_NETDEV__ > + > +#include "virtio_rdma.h" > + > +struct virtio_rdma_netdev_info { > + struct virtio_rdma_info *ri; > +}; > + > +int init_netdev(struct virtio_rdma_info *ri); > +void fini_netdev(struct virtio_rdma_info *ri); > + > +#endif > diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h > index 6d5c3b2d4f4d..288ee6fec8d3 100644 > --- a/include/uapi/linux/virtio_ids.h > +++ b/include/uapi/linux/virtio_ids.h > @@ -43,5 +43,6 @@ > #define VIRTIO_ID_INPUT 18 /* virtio input */ > #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ > #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ > +#define VIRTIO_ID_RDMA 26 /* RDMA */ > > #endif /* _LINUX_VIRTIO_IDS_H */
> > + > > + wake_up(&dev->acked); > > + > > + printk("%s\n", __func__); > > Cool:-) > > this line should be for debug? Yes > > Zhu Yanjun >
On 4/11/19 4:01 AM, Yuval Shaia wrote: > +++ b/drivers/infiniband/hw/virtio/Kconfig > @@ -0,0 +1,6 @@ > +config INFINIBAND_VIRTIO_RDMA > + tristate "VirtIO Paravirtualized RDMA Driver" > + depends on NETDEVICES && ETHERNET && PCI && INET > + ---help--- > + This driver provides low-level support for VirtIO Paravirtual > + RDMA adapter. Does this driver really depend on Ethernet, or does it also work with Ethernet support disabled? > +static inline struct virtio_rdma_info *to_vdev(struct ib_device *ibdev) > +{ > + return container_of(ibdev, struct virtio_rdma_info, ib_dev); > +} Is it really worth to introduce this function? Have you considered to use container_of(ibdev, struct virtio_rdma_info, ib_dev) directly instead of to_vdev()? > +static void rdma_ctrl_ack(struct virtqueue *vq) > +{ > + struct virtio_rdma_info *dev = vq->vdev->priv; > + > + wake_up(&dev->acked); > + > + printk("%s\n", __func__); > +} Should that printk() be changed into pr_debug()? The same comment holds for all other printk() calls. > +#define VIRTIO_RDMA_BOARD_ID 1 > +#define VIRTIO_RDMA_HW_NAME "virtio-rdma" > +#define VIRTIO_RDMA_HW_REV 1 > +#define VIRTIO_RDMA_DRIVER_VER "1.0" Is a driver version number useful in an upstream driver? > +struct ib_cq *virtio_rdma_create_cq(struct ib_device *ibdev, > + const struct ib_cq_init_attr *attr, > + struct ib_ucontext *context, > + struct ib_udata *udata) > +{ > + struct scatterlist in, out; > + struct virtio_rdma_ib_cq *vcq; > + struct cmd_create_cq *cmd; > + struct rsp_create_cq *rsp; > + struct ib_cq *cq = NULL; > + int rc; > + > + /* TODO: Check MAX_CQ */ > + > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > + if (!cmd) > + return ERR_PTR(-ENOMEM); > + > + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); > + if (!rsp) { > + kfree(cmd); > + return ERR_PTR(-ENOMEM); > + } > + > + vcq = kzalloc(sizeof(*vcq), GFP_KERNEL); > + if (!vcq) > + goto out; Are you sure that you want to mix GFP_ATOMIC and GFP_KERNEL in a single function? Thanks, Bart.
On Mon, Apr 15, 2019 at 06:07:52PM -0700, Bart Van Assche wrote: > On 4/11/19 4:01 AM, Yuval Shaia wrote: > > +++ b/drivers/infiniband/hw/virtio/Kconfig > > @@ -0,0 +1,6 @@ > > +config INFINIBAND_VIRTIO_RDMA > > + tristate "VirtIO Paravirtualized RDMA Driver" > > + depends on NETDEVICES && ETHERNET && PCI && INET > > + ---help--- > > + This driver provides low-level support for VirtIO Paravirtual > > + RDMA adapter. > > Does this driver really depend on Ethernet, or does it also work with > Ethernet support disabled? The device should eventually expose Ethernet interface as well as IB. > > > +static inline struct virtio_rdma_info *to_vdev(struct ib_device *ibdev) > > +{ > > + return container_of(ibdev, struct virtio_rdma_info, ib_dev); > > +} > > Is it really worth to introduce this function? Have you considered to > use container_of(ibdev, struct virtio_rdma_info, ib_dev) directly instead > of to_vdev()? Agree, not sure really needed, just saw that some drivers uses this pattern. > > > +static void rdma_ctrl_ack(struct virtqueue *vq) > > +{ > > + struct virtio_rdma_info *dev = vq->vdev->priv; > > + > > + wake_up(&dev->acked); > > + > > + printk("%s\n", __func__); > > +} > > Should that printk() be changed into pr_debug()? The same comment holds for > all other printk() calls. All prints will be removed, this is still wip. > > > +#define VIRTIO_RDMA_BOARD_ID 1 > > +#define VIRTIO_RDMA_HW_NAME "virtio-rdma" > > +#define VIRTIO_RDMA_HW_REV 1 > > +#define VIRTIO_RDMA_DRIVER_VER "1.0" > > Is a driver version number useful in an upstream driver? I've noticed that other drivers exposes this in sysfs. > > > +struct ib_cq *virtio_rdma_create_cq(struct ib_device *ibdev, > > + const struct ib_cq_init_attr *attr, > > + struct ib_ucontext *context, > > + struct ib_udata *udata) > > +{ > > + struct scatterlist in, out; > > + struct virtio_rdma_ib_cq *vcq; > > + struct cmd_create_cq *cmd; > > + struct rsp_create_cq *rsp; > > + struct ib_cq *cq = NULL; > > + int rc; > > + > > + /* TODO: Check MAX_CQ */ > > + > > + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); > > + if (!cmd) > > + return ERR_PTR(-ENOMEM); > > + > > + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); > > + if (!rsp) { > > + kfree(cmd); > > + return ERR_PTR(-ENOMEM); > > + } > > + > > + vcq = kzalloc(sizeof(*vcq), GFP_KERNEL); > > + if (!vcq) > > + goto out; > > Are you sure that you want to mix GFP_ATOMIC and GFP_KERNEL in a single > function? Right, a mistake. > > Thanks, > > Bart. Thanks. >
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index a1fb840de45d..218a47d4cecf 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -107,6 +107,7 @@ source "drivers/infiniband/hw/hfi1/Kconfig" source "drivers/infiniband/hw/qedr/Kconfig" source "drivers/infiniband/sw/rdmavt/Kconfig" source "drivers/infiniband/sw/rxe/Kconfig" +source "drivers/infiniband/hw/virtio/Kconfig" endif source "drivers/infiniband/ulp/ipoib/Kconfig" diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile index e4f31c1be8f7..10ffb2c421e4 100644 --- a/drivers/infiniband/hw/Makefile +++ b/drivers/infiniband/hw/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ obj-$(CONFIG_INFINIBAND_HNS) += hns/ obj-$(CONFIG_INFINIBAND_QEDR) += qedr/ obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re/ +obj-$(CONFIG_INFINIBAND_VIRTIO_RDMA) += virtio/ diff --git a/drivers/infiniband/hw/virtio/Kconfig b/drivers/infiniband/hw/virtio/Kconfig new file mode 100644 index 000000000000..92e41691cf5d --- /dev/null +++ b/drivers/infiniband/hw/virtio/Kconfig @@ -0,0 +1,6 @@ +config INFINIBAND_VIRTIO_RDMA + tristate "VirtIO Paravirtualized RDMA Driver" + depends on NETDEVICES && ETHERNET && PCI && INET + ---help--- + This driver provides low-level support for VirtIO Paravirtual + RDMA adapter. diff --git a/drivers/infiniband/hw/virtio/Makefile b/drivers/infiniband/hw/virtio/Makefile new file mode 100644 index 000000000000..fb637e467167 --- /dev/null +++ b/drivers/infiniband/hw/virtio/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_INFINIBAND_VIRTIO_RDMA) += virtio_rdma.o + +virtio_rdma-y := virtio_rdma_main.o virtio_rdma_device.o virtio_rdma_ib.o \ + virtio_rdma_netdev.o diff --git a/drivers/infiniband/hw/virtio/virtio_rdma.h b/drivers/infiniband/hw/virtio/virtio_rdma.h new file mode 100644 index 000000000000..7896a2dfb812 --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma.h @@ -0,0 +1,40 @@ +/* + * Virtio RDMA device: Driver main data types + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VIRTIO_RDMA__ +#define __VIRTIO_RDMA__ + +#include <linux/virtio.h> +#include <rdma/ib_verbs.h> + +struct virtio_rdma_info { + struct ib_device ib_dev; + struct virtio_device *vdev; + struct virtqueue *ctrl_vq; + wait_queue_head_t acked; /* arm on send to host, release on recv */ + struct net_device *netdev; +}; + +static inline struct virtio_rdma_info *to_vdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct virtio_rdma_info, ib_dev); +} + +#endif diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_device.c b/drivers/infiniband/hw/virtio/virtio_rdma_device.c new file mode 100644 index 000000000000..ae41e530644f --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_device.c @@ -0,0 +1,59 @@ +/* + * Virtio RDMA device: Device related functions and data + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/virtio_config.h> + +#include "virtio_rdma.h" + +static void rdma_ctrl_ack(struct virtqueue *vq) +{ + struct virtio_rdma_info *dev = vq->vdev->priv; + + wake_up(&dev->acked); + + printk("%s\n", __func__); +} + +int init_device(struct virtio_rdma_info *dev) +{ +#define TMP_MAX_VQ 1 + int rc; + struct virtqueue *vqs[TMP_MAX_VQ]; + vq_callback_t *cbs[TMP_MAX_VQ]; + const char *names[TMP_MAX_VQ]; + + names[0] = "ctrl"; + cbs[0] = rdma_ctrl_ack; + cbs[0] = NULL; + + rc = virtio_find_vqs(dev->vdev, TMP_MAX_VQ, vqs, cbs, names, NULL); + if (rc) + return rc; + + dev->ctrl_vq = vqs[0]; + + return 0; +} + +void fini_device(struct virtio_rdma_info *dev) +{ + dev->vdev->config->reset(dev->vdev); + dev->vdev->config->del_vqs(dev->vdev); +} diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_device.h b/drivers/infiniband/hw/virtio/virtio_rdma_device.h new file mode 100644 index 000000000000..d9b1240daf92 --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_device.h @@ -0,0 +1,32 @@ +/* + * Virtio RDMA device: Device related functions and data + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VIRTIO_RDMA_DEVICE__ +#define __VIRTIO_RDMA_DEVICE__ + +#define VIRTIO_RDMA_BOARD_ID 1 +#define VIRTIO_RDMA_HW_NAME "virtio-rdma" +#define VIRTIO_RDMA_HW_REV 1 +#define VIRTIO_RDMA_DRIVER_VER "1.0" + +int init_device(struct virtio_rdma_info *dev); +void fini_device(struct virtio_rdma_info *dev); + +#endif diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_ib.c b/drivers/infiniband/hw/virtio/virtio_rdma_ib.c new file mode 100644 index 000000000000..02bf4a332611 --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_ib.c @@ -0,0 +1,711 @@ +/* + * Virtio RDMA device: IB related functions and data + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/scatterlist.h> +#include <linux/virtio.h> +#include <rdma/ib_mad.h> + +#include "virtio_rdma.h" +#include "virtio_rdma_device.h" +#include "virtio_rdma_ib.h" + +/* TODO: Move to uapi header file */ + +/* + * Control virtqueue data structures + * + * The control virtqueue expects a header in the first sg entry + * and an ack/status response in the last entry. Data for the + * command goes in between. + */ + +#define VIRTIO_RDMA_CTRL_OK 0 +#define VIRTIO_RDMA_CTRL_ERR 1 + +struct control_buf { + __u8 cmd; + __u8 status; +}; + +enum { + VIRTIO_CMD_QUERY_DEVICE = 10, + VIRTIO_CMD_QUERY_PORT, + VIRTIO_CMD_CREATE_CQ, + VIRTIO_CMD_DESTROY_CQ, + VIRTIO_CMD_CREATE_PD, + VIRTIO_CMD_DESTROY_PD, + VIRTIO_CMD_GET_DMA_MR, +}; + +struct cmd_query_port { + __u8 port; +}; + +struct cmd_create_cq { + __u32 cqe; +}; + +struct rsp_create_cq { + __u32 cqn; +}; + +struct cmd_destroy_cq { + __u32 cqn; +}; + +struct rsp_create_pd { + __u32 pdn; +}; + +struct cmd_destroy_pd { + __u32 pdn; +}; + +struct cmd_get_dma_mr { + __u32 pdn; + __u32 access_flags; +}; + +struct rsp_get_dma_mr { + __u32 mrn; + __u32 lkey; + __u32 rkey; +}; + +/* TODO: Move to uapi header file */ + +struct virtio_rdma_ib_cq { + struct ib_cq ibcq; + u32 cq_handle; +}; + +/* TODO: For the scope fof the RFC i'm utilizing ib*_*_attr structures */ + +static int virtio_rdma_exec_cmd(struct virtio_rdma_info *di, int cmd, + struct scatterlist *in, struct scatterlist *out) +{ + struct scatterlist *sgs[4], hdr, status; + struct control_buf *ctrl; + unsigned tmp; + int rc; + + ctrl = kmalloc(sizeof(*ctrl), GFP_ATOMIC); + ctrl->cmd = cmd; + ctrl->status = ~0; + + sg_init_one(&hdr, &ctrl->cmd, sizeof(ctrl->cmd)); + sgs[0] = &hdr; + sgs[1] = in; + sgs[2] = out; + sg_init_one(&status, &ctrl->status, sizeof(ctrl->status)); + sgs[3] = &status; + + rc = virtqueue_add_sgs(di->ctrl_vq, sgs, 2, 2, di, GFP_ATOMIC); + if (rc) + goto out; + + if (unlikely(!virtqueue_kick(di->ctrl_vq))) { + goto out_with_status; + } + + /* Spin for a response, the kick causes an ioport write, trapping + * into the hypervisor, so the request should be handled + * immediately */ + while (!virtqueue_get_buf(di->ctrl_vq, &tmp) && + !virtqueue_is_broken(di->ctrl_vq)) + cpu_relax(); + +out_with_status: + printk("%s: cmd %d, status %d\n", __func__, ctrl->cmd, ctrl->status); + rc = ctrl->status == VIRTIO_RDMA_CTRL_OK ? 0 : 1; + +out: + kfree(ctrl); + + return rc; +} + +static int virtio_rdma_port_immutable(struct ib_device *ibdev, u8 port_num, + struct ib_port_immutable *immutable) +{ + struct ib_port_attr attr; + int rc; + + rc = ib_query_port(ibdev, port_num, &attr); + if (rc) + return rc; + + immutable->core_cap_flags |= RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; + immutable->pkey_tbl_len = attr.pkey_tbl_len; + immutable->gid_tbl_len = attr.gid_tbl_len; + immutable->max_mad_size = IB_MGMT_MAD_SIZE; + + return 0; +} + +static int virtio_rdma_query_device(struct ib_device *ibdev, + struct ib_device_attr *props, + struct ib_udata *uhw) +{ + struct scatterlist data; + int offs; + int rc; + + if (uhw->inlen || uhw->outlen) + return -EINVAL; + + /* We start with sys_image_guid because of inconsistency beween ib_ + * and ibv_ */ + offs = offsetof(struct ib_device_attr, sys_image_guid); + sg_init_one(&data, (void *)props + offs, sizeof(*props) - offs); + + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_QUERY_DEVICE, NULL, + &data); + + printk("%s: sys_image_guid 0x%llx\n", __func__, + be64_to_cpu(props->sys_image_guid)); + + return rc; +} + +static int virtio_rdma_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props) +{ + struct scatterlist in, out; + struct cmd_query_port *cmd; + int offs; + int rc; + + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + /* We start with state because of inconsistency beween ib and ibv */ + offs = offsetof(struct ib_port_attr, state); + sg_init_one(&out, (void *)props + offs, sizeof(*props) - offs); + + cmd->port = port; + sg_init_one(&in, cmd, sizeof(*cmd)); + printk("%s: port %d\n", __func__, cmd->port); + + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_QUERY_PORT, &in, + &out); + + printk("%s: gid_tbl_len %d\n", __func__, props->gid_tbl_len); + + kfree(cmd); + + return rc; +} + +static struct net_device *virtio_rdma_get_netdev(struct ib_device *ibdev, + u8 port_num) +{ + struct virtio_rdma_info *ri = to_vdev(ibdev); + + printk("%s:\n", __func__); + + return ri->netdev; +} + +struct ib_cq *virtio_rdma_create_cq(struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct scatterlist in, out; + struct virtio_rdma_ib_cq *vcq; + struct cmd_create_cq *cmd; + struct rsp_create_cq *rsp; + struct ib_cq *cq = NULL; + int rc; + + /* TODO: Check MAX_CQ */ + + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + return ERR_PTR(-ENOMEM); + + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); + if (!rsp) { + kfree(cmd); + return ERR_PTR(-ENOMEM); + } + + vcq = kzalloc(sizeof(*vcq), GFP_KERNEL); + if (!vcq) + goto out; + + cmd->cqe = attr->cqe; + sg_init_one(&in, cmd, sizeof(*cmd)); + printk("%s: cqe %d\n", __func__, cmd->cqe); + + sg_init_one(&out, rsp, sizeof(*rsp)); + + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_CREATE_CQ, &in, + &out); + if (rc) + goto out_err; + + printk("%s: cqn 0x%x\n", __func__, rsp->cqn); + vcq->cq_handle = rsp->cqn; + vcq->ibcq.cqe = attr->cqe; + cq = &vcq->ibcq; + + goto out; + +out_err: + kfree(vcq); + return ERR_PTR(rc); + +out: + kfree(rsp); + kfree(cmd); + return cq; +} + +int virtio_rdma_destroy_cq(struct ib_cq *cq) +{ + struct virtio_rdma_ib_cq *vcq; + struct scatterlist in; + struct cmd_destroy_cq *cmd; + int rc; + + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + vcq = container_of(cq, struct virtio_rdma_ib_cq, ibcq); + + cmd->cqn = vcq->cq_handle; + sg_init_one(&in, cmd, sizeof(*cmd)); + + rc = virtio_rdma_exec_cmd(to_vdev(cq->device), VIRTIO_CMD_DESTROY_CQ, + &in, NULL); + + kfree(cmd); + + kfree(vcq); + + return rc; +} + +int virtio_rdma_alloc_pd(struct ib_pd *ibpd, struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct virtio_rdma_pd *pd = to_vpd(ibpd); + struct ib_device *ibdev = ibpd->device; + struct rsp_create_pd *rsp; + struct scatterlist out; + int rc; + + /* TODO: Check MAX_PD */ + + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); + if (!rsp) + return -ENOMEM; + + sg_init_one(&out, rsp, sizeof(*rsp)); + + rc = virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_CREATE_PD, NULL, + &out); + if (rc) + goto out; + + pd->pd_handle = rsp->pdn; + + printk("%s: pd_handle=%d\n", __func__, pd->pd_handle); + +out: + kfree(rsp); + + printk("%s: rc=%d\n", __func__, rc); + return rc; +} + +void virtio_rdma_dealloc_pd(struct ib_pd *pd) +{ + struct virtio_rdma_pd *vpd = to_vpd(pd); + struct ib_device *ibdev = pd->device; + struct cmd_destroy_pd *cmd; + struct scatterlist in; + + printk("%s:\n", __func__); + + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + return; + + cmd->pdn = vpd->pd_handle; + sg_init_one(&in, cmd, sizeof(*cmd)); + + virtio_rdma_exec_cmd(to_vdev(ibdev), VIRTIO_CMD_DESTROY_PD, &in, NULL); + + kfree(cmd); +} + +struct ib_mr *virtio_rdma_get_dma_mr(struct ib_pd *pd, int acc) + +{ + struct virtio_rdma_user_mr *mr; + struct scatterlist in, out; + struct cmd_get_dma_mr *cmd = NULL; + struct rsp_get_dma_mr *rsp = NULL; + int rc; + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) { + kfree(mr); + return ERR_PTR(-ENOMEM); + } + + rsp = kmalloc(sizeof(*rsp), GFP_ATOMIC); + if (!cmd) { + kfree(mr); + kfree(cmd); + return ERR_PTR(-ENOMEM); + } + + cmd->pdn = to_vpd(pd)->pd_handle; + cmd->access_flags = acc; + sg_init_one(&in, cmd, sizeof(*cmd)); + + sg_init_one(&out, rsp, sizeof(*rsp)); + + rc = virtio_rdma_exec_cmd(to_vdev(pd->device), VIRTIO_CMD_GET_DMA_MR, + &in, &out); + if (rc) { + kfree(mr); + kfree(cmd); + return ERR_PTR(rc); + } + + mr->mr_handle = rsp->mrn; + mr->ibmr.lkey = rsp->lkey; + mr->ibmr.rkey = rsp->rkey; + + printk("%s: mr_handle=0x%x\n", __func__, mr->mr_handle); + + kfree(cmd); + kfree(rsp); + + return &mr->ibmr; +} + +struct ib_qp *virtio_rdma_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + /* struct pvrdma_dev *dev = to_vdev(pd->device); */ + struct virtio_rdma_qp *qp; + + printk("%s:\n", __func__); + + qp = kzalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + return &qp->ibqp; +} + +int virtio_rdma_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *gid) +{ + memset(gid, 0, sizeof(union ib_gid)); + + printk("%s: port %d, index %d\n", __func__, port, index); + + return 0; +} + +static int virtio_rdma_add_gid(const struct ib_gid_attr *attr, void **context) +{ + printk("%s:\n", __func__); + + return 0; +} + +struct ib_mr *virtio_rdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg) +{ + printk("%s: mr_type %d, max_num_sg %d\n", __func__, mr_type, + max_num_sg); + + return NULL; +} + +int virtio_rdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata) +{ + printk("%s:\n", __func__); + + return 0; +} + +struct ib_ah *virtio_rdma_create_ah(struct ib_pd *pd, + struct rdma_ah_attr *ah_attr, u32 flags, + struct ib_udata *udata) +{ + printk("%s:\n", __func__); + + return NULL; +} + +void virtio_rdma_dealloc_ucontext(struct ib_ucontext *ibcontext) + +{ +} + +static int virtio_rdma_del_gid(const struct ib_gid_attr *attr, void **context) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_dereg_mr(struct ib_mr *ibmr) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_destroy_ah(struct ib_ah *ah, u32 flags) +{ + printk("%s:\n", __func__); + + return 0; +} + +struct virtio_rdma_cq { + struct ib_cq ibcq; +}; + +int virtio_rdma_destroy_qp(struct ib_qp *qp) +{ + printk("%s:\n", __func__); + + return 0; +} + +static void virtio_rdma_get_fw_ver_str(struct ib_device *device, char *str) +{ + printk("%s:\n", __func__); +} + +enum rdma_link_layer virtio_rdma_port_link_layer(struct ib_device *ibdev, + u8 port) +{ + return IB_LINK_LAYER_ETHERNET; +} + +int virtio_rdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, + int sg_nents, unsigned int *sg_offset) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_modify_port(struct ib_device *ibdev, u8 port, int mask, + struct ib_port_modify *props) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, + const struct ib_recv_wr **bad_wr) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, + const struct ib_send_wr **bad_wr) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, + u16 *pkey) +{ + printk("%s:\n", __func__); + + return 0; +} + +int virtio_rdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr) +{ + printk("%s:\n", __func__); + + return 0; +} + +struct ib_mr *virtio_rdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata) +{ + printk("%s:\n", __func__); + + return NULL; +} + +int virtio_rdma_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags notify_flags) +{ + printk("%s:\n", __func__); + + return 0; +} + +static const struct ib_device_ops virtio_rdma_dev_ops = { + .get_port_immutable = virtio_rdma_port_immutable, + .query_device = virtio_rdma_query_device, + .query_port = virtio_rdma_query_port, + .get_netdev = virtio_rdma_get_netdev, + .create_cq = virtio_rdma_create_cq, + .destroy_cq = virtio_rdma_destroy_cq, + .alloc_pd = virtio_rdma_alloc_pd, + .dealloc_pd = virtio_rdma_dealloc_pd, + .get_dma_mr = virtio_rdma_get_dma_mr, + .create_qp = virtio_rdma_create_qp, + .query_gid = virtio_rdma_query_gid, + .add_gid = virtio_rdma_add_gid, + .alloc_mr = virtio_rdma_alloc_mr, + .alloc_ucontext = virtio_rdma_alloc_ucontext, + .create_ah = virtio_rdma_create_ah, + .dealloc_ucontext = virtio_rdma_dealloc_ucontext, + .del_gid = virtio_rdma_del_gid, + .dereg_mr = virtio_rdma_dereg_mr, + .destroy_ah = virtio_rdma_destroy_ah, + .destroy_qp = virtio_rdma_destroy_qp, + .get_dev_fw_str = virtio_rdma_get_fw_ver_str, + .get_link_layer = virtio_rdma_port_link_layer, + .get_port_immutable = virtio_rdma_port_immutable, + .map_mr_sg = virtio_rdma_map_mr_sg, + .mmap = virtio_rdma_mmap, + .modify_port = virtio_rdma_modify_port, + .modify_qp = virtio_rdma_modify_qp, + .poll_cq = virtio_rdma_poll_cq, + .post_recv = virtio_rdma_post_recv, + .post_send = virtio_rdma_post_send, + .query_device = virtio_rdma_query_device, + .query_pkey = virtio_rdma_query_pkey, + .query_port = virtio_rdma_query_port, + .query_qp = virtio_rdma_query_qp, + .reg_user_mr = virtio_rdma_reg_user_mr, + .req_notify_cq = virtio_rdma_req_notify_cq, + INIT_RDMA_OBJ_SIZE(ib_pd, virtio_rdma_pd, ibpd), +}; + +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s-%s\n", VIRTIO_RDMA_HW_NAME, + VIRTIO_RDMA_DRIVER_VER); +} +static DEVICE_ATTR_RO(hca_type); + +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", VIRTIO_RDMA_HW_REV); +} +static DEVICE_ATTR_RO(hw_rev); + +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", VIRTIO_RDMA_BOARD_ID); +} +static DEVICE_ATTR_RO(board_id); + +static struct attribute *virtio_rdmaa_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL, +}; + +static const struct attribute_group virtio_rdmaa_attr_group = { + .attrs = virtio_rdmaa_class_attributes, +}; + +int init_ib(struct virtio_rdma_info *ri) +{ + int rc; + + ri->ib_dev.owner = THIS_MODULE; + ri->ib_dev.num_comp_vectors = 1; + ri->ib_dev.dev.parent = &ri->vdev->dev; + ri->ib_dev.node_type = RDMA_NODE_IB_CA; + ri->ib_dev.phys_port_cnt = 1; + ri->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD); + + rdma_set_device_sysfs_group(&ri->ib_dev, &virtio_rdmaa_attr_group); + + ib_set_device_ops(&ri->ib_dev, &virtio_rdma_dev_ops); + + rc = ib_register_device(&ri->ib_dev, "virtio_rdma%d"); + + return rc; +} + +void fini_ib(struct virtio_rdma_info *ri) +{ + ib_unregister_device(&ri->ib_dev); +} diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_ib.h b/drivers/infiniband/hw/virtio/virtio_rdma_ib.h new file mode 100644 index 000000000000..7b82a60581ff --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_ib.h @@ -0,0 +1,48 @@ +/* + * Virtio RDMA device: IB related functions and data + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VIRTIO_RDMA_IB__ +#define __VIRTIO_RDMA_IB__ + +#include <rdma/ib_verbs.h> + +struct virtio_rdma_pd { + struct ib_pd ibpd; + u32 pd_handle; +}; + +struct virtio_rdma_user_mr { + struct ib_mr ibmr; + u32 mr_handle; +}; + +struct virtio_rdma_qp { + struct ib_qp ibqp; +}; + +static inline struct virtio_rdma_pd *to_vpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct virtio_rdma_pd, ibpd); +} + +int init_ib(struct virtio_rdma_info *ri); +void fini_ib(struct virtio_rdma_info *ri); + +#endif diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_main.c b/drivers/infiniband/hw/virtio/virtio_rdma_main.c new file mode 100644 index 000000000000..811533d63160 --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_main.c @@ -0,0 +1,149 @@ +/* + * Virtio RDMA device + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/err.h> +#include <linux/scatterlist.h> +#include <linux/spinlock.h> +#include <linux/virtio.h> +#include <linux/module.h> +#include <uapi/linux/virtio_ids.h> + +#include "virtio_rdma.h" +#include "virtio_rdma_device.h" +#include "virtio_rdma_ib.h" +#include "virtio_rdma_netdev.h" + +/* TODO: + * - How to hook to unload driver, we need to undo all the stuff with did + * for all the devices that probed + * - + */ + +static int virtio_rdma_probe(struct virtio_device *vdev) +{ + struct virtio_rdma_info *ri; + int rc = -EIO; + + ri = ib_alloc_device(virtio_rdma_info, ib_dev); + if (!ri) { + pr_err("Fail to allocate IB device\n"); + rc = -ENOMEM; + goto out; + } + vdev->priv = ri; + + ri->vdev = vdev; + + rc = init_device(ri); + if (rc) { + pr_err("Fail to connect to device\n"); + goto out_dealloc_ib_device; + } + + rc = init_netdev(ri); + if (rc) { + pr_err("Fail to connect to NetDev layer\n"); + goto out_fini_device; + } + + rc = init_ib(ri); + if (rc) { + pr_err("Fail to connect to IB layer\n"); + goto out_fini_netdev; + } + + pr_info("VirtIO RDMA device %d probed\n", vdev->index); + + goto out; + +out_fini_netdev: + fini_netdev(ri); + +out_fini_device: + fini_device(ri); + +out_dealloc_ib_device: + ib_dealloc_device(&ri->ib_dev); + + vdev->priv = NULL; + +out: + return rc; +} + +static void virtio_rdma_remove(struct virtio_device *vdev) +{ + struct virtio_rdma_info *ri = vdev->priv; + + if (!ri) + return; + + vdev->priv = NULL; + + fini_ib(ri); + + fini_netdev(ri); + + fini_device(ri); + + ib_dealloc_device(&ri->ib_dev); + + pr_info("VirtIO RDMA device %d removed\n", vdev->index); +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_RDMA, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_rdma_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_rdma_probe, + .remove = virtio_rdma_remove, +}; + +static int __init virtio_rdma_init(void) +{ + int rc; + + rc = register_virtio_driver(&virtio_rdma_driver); + if (rc) { + pr_err("%s: Fail to register virtio driver (%d)\n", __func__, + rc); + return rc; + } + + return 0; +} + +static void __exit virtio_rdma_fini(void) +{ + unregister_virtio_driver(&virtio_rdma_driver); +} + +module_init(virtio_rdma_init); +module_exit(virtio_rdma_fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_AUTHOR("Yuval Shaia"); +MODULE_DESCRIPTION("Virtio RDMA driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c new file mode 100644 index 000000000000..001f30b3e0b9 --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.c @@ -0,0 +1,44 @@ +/* + * Virtio RDMA device + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "virtio_rdma_netdev.h" + +int init_netdev(struct virtio_rdma_info *ri) +{ + struct net_device *dev; + struct virtio_rdma_netdev_info *vrndi; + + dev = alloc_etherdev(sizeof(struct virtio_rdma_netdev_info)); + if (!dev) { + return -ENOMEM; + } + + SET_NETDEV_DEV(dev, &ri->vdev->dev); + vrndi = netdev_priv(dev); + vrndi->ri = ri; + ri->netdev = dev; + + return 0; +} + +void fini_netdev(struct virtio_rdma_info *ri) +{ + unregister_netdev(ri->netdev); +} diff --git a/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h new file mode 100644 index 000000000000..e7e5d276d8ec --- /dev/null +++ b/drivers/infiniband/hw/virtio/virtio_rdma_netdev.h @@ -0,0 +1,33 @@ +/* + * Virtio RDMA device: Netdev related functions and data + * + * Copyright (C) 2019 Yuval Shaia Oracle Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VIRTIO_RDMA_NETDEV__ +#define __VIRTIO_RDMA_NETDEV__ + +#include "virtio_rdma.h" + +struct virtio_rdma_netdev_info { + struct virtio_rdma_info *ri; +}; + +int init_netdev(struct virtio_rdma_info *ri); +void fini_netdev(struct virtio_rdma_info *ri); + +#endif diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 6d5c3b2d4f4d..288ee6fec8d3 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -43,5 +43,6 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_RDMA 26 /* RDMA */ #endif /* _LINUX_VIRTIO_IDS_H */
Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com> --- drivers/infiniband/Kconfig | 1 + drivers/infiniband/hw/Makefile | 1 + drivers/infiniband/hw/virtio/Kconfig | 6 + drivers/infiniband/hw/virtio/Makefile | 4 + drivers/infiniband/hw/virtio/virtio_rdma.h | 40 + .../infiniband/hw/virtio/virtio_rdma_device.c | 59 ++ .../infiniband/hw/virtio/virtio_rdma_device.h | 32 + drivers/infiniband/hw/virtio/virtio_rdma_ib.c | 711 ++++++++++++++++++ drivers/infiniband/hw/virtio/virtio_rdma_ib.h | 48 ++ .../infiniband/hw/virtio/virtio_rdma_main.c | 149 ++++ .../infiniband/hw/virtio/virtio_rdma_netdev.c | 44 ++ .../infiniband/hw/virtio/virtio_rdma_netdev.h | 33 + include/uapi/linux/virtio_ids.h | 1 + 13 files changed, 1129 insertions(+) create mode 100644 drivers/infiniband/hw/virtio/Kconfig create mode 100644 drivers/infiniband/hw/virtio/Makefile create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma.h create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_device.c create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_device.h create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_ib.c create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_ib.h create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_main.c create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_netdev.c create mode 100644 drivers/infiniband/hw/virtio/virtio_rdma_netdev.h