Unified · Split
| @@ -12924,6 +12924,13 @@ S: Maintained · 12923 unmodified lines | ||
| 12924 | 12924 | F: drivers/scsi/vmw_pvscsi.c |
| 12925 | 12925 | F: drivers/scsi/vmw_pvscsi.h |
| 12926 | 12926 | |
| 12927 | +VMWARE PVRDMA DRIVER | |
| 12928 | +M: Adit Ranadive <aditr@vmware.com> | |
| 12929 | +M: VMware PV-Drivers <pv-drivers@vmware.com> | |
| 12930 | +L: linux-rdma@vger.kernel.org | |
| 12931 | +S: Maintained | |
| 12932 | +F: drivers/infiniband/hw/vmw_pvrdma/ | |
| 12933 | + | |
| 12927 | 12934 | VOLTAGE AND CURRENT REGULATOR FRAMEWORK |
| 12928 | 12935 | M: Liam Girdwood <lgirdwood@gmail.com> |
| 12929 | 12936 | M: Mark Brown <broonie@kernel.org> |
| @@ -73,6 +73,7 @@ source "drivers/infiniband/hw/mlx4/Kconfig" · 72 unmodified lines | ||
| 73 | 73 | source "drivers/infiniband/hw/mlx5/Kconfig" |
| 74 | 74 | source "drivers/infiniband/hw/nes/Kconfig" |
| 75 | 75 | source "drivers/infiniband/hw/ocrdma/Kconfig" |
| 76 | +source "drivers/infiniband/hw/vmw_pvrdma/Kconfig" | |
| 76 | 77 | source "drivers/infiniband/hw/usnic/Kconfig" |
| 77 | 78 | source "drivers/infiniband/hw/hns/Kconfig" |
| 78 | 79 | |
| @@ -7,6 +7,7 @@ obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/ · 6 unmodified lines | ||
| 7 | 7 | obj-$(CONFIG_MLX5_INFINIBAND) += mlx5/ |
| 8 | 8 | obj-$(CONFIG_INFINIBAND_NES) += nes/ |
| 9 | 9 | obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/ |
| 10 | +obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma/ | |
| 10 | 11 | obj-$(CONFIG_INFINIBAND_USNIC) += usnic/ |
| 11 | 12 | obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ |
| 12 | 13 | obj-$(CONFIG_INFINIBAND_HNS) += hns/ |
| @@ -0,0 +1,7 @@ | ||
| 1 | +config INFINIBAND_VMWARE_PVRDMA | |
| 2 | + tristate "VMware Paravirtualized RDMA Driver" | |
| 3 | + depends on NETDEVICES && ETHERNET && PCI && INET && VMXNET3 | |
| 4 | + ---help--- | |
| 5 | + This driver provides low-level support for VMware Paravirtual | |
| 6 | + RDMA adapter. It interacts with the VMXNet3 driver to provide | |
| 7 | + Ethernet capabilities. | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma.o | |
| 2 | + | |
| 3 | +vmw_pvrdma-y := pvrdma_cmd.o pvrdma_cq.o pvrdma_doorbell.o pvrdma_main.o pvrdma_misc.o pvrdma_mr.o pvrdma_qp.o pvrdma_verbs.o | |
| @@ -0,0 +1,474 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#ifndef __PVRDMA_H__ | |
| 47 | +#define __PVRDMA_H__ | |
| 48 | + | |
| 49 | +#include <linux/compiler.h> | |
| 50 | +#include <linux/interrupt.h> | |
| 51 | +#include <linux/list.h> | |
| 52 | +#include <linux/mutex.h> | |
| 53 | +#include <linux/pci.h> | |
| 54 | +#include <linux/semaphore.h> | |
| 55 | +#include <linux/workqueue.h> | |
| 56 | +#include <rdma/ib_umem.h> | |
| 57 | +#include <rdma/ib_verbs.h> | |
| 58 | +#include <rdma/vmw_pvrdma-abi.h> | |
| 59 | + | |
| 60 | +#include "pvrdma_ring.h" | |
| 61 | +#include "pvrdma_dev_api.h" | |
| 62 | +#include "pvrdma_verbs.h" | |
| 63 | + | |
| 64 | +/* NOT the same as BIT_MASK(). */ | |
| 65 | +#define PVRDMA_MASK(n) ((n << 1) - 1) | |
| 66 | + | |
| 67 | +/* | |
| 68 | + * VMware PVRDMA PCI device id. | |
| 69 | + */ | |
| 70 | +#define PCI_DEVICE_ID_VMWARE_PVRDMA 0x0820 | |
| 71 | + | |
| 72 | +struct pvrdma_dev; | |
| 73 | + | |
| 74 | +struct pvrdma_page_dir { | |
| 75 | + dma_addr_t dir_dma; | |
| 76 | + u64 *dir; | |
| 77 | + int ntables; | |
| 78 | + u64 **tables; | |
| 79 | + u64 npages; | |
| 80 | + void **pages; | |
| 81 | +}; | |
| 82 | + | |
| 83 | +struct pvrdma_cq { | |
| 84 | + struct ib_cq ibcq; | |
| 85 | + int offset; | |
| 86 | + spinlock_t cq_lock; /* Poll lock. */ | |
| 87 | + struct pvrdma_uar_map *uar; | |
| 88 | + struct ib_umem *umem; | |
| 89 | + struct pvrdma_ring_state *ring_state; | |
| 90 | + struct pvrdma_page_dir pdir; | |
| 91 | + u32 cq_handle; | |
| 92 | + bool is_kernel; | |
| 93 | + atomic_t refcnt; | |
| 94 | + wait_queue_head_t wait; | |
| 95 | +}; | |
| 96 | + | |
| 97 | +struct pvrdma_id_table { | |
| 98 | + u32 last; | |
| 99 | + u32 top; | |
| 100 | + u32 max; | |
| 101 | + u32 mask; | |
| 102 | + spinlock_t lock; /* Table lock. */ | |
| 103 | + unsigned long *table; | |
| 104 | +}; | |
| 105 | + | |
| 106 | +struct pvrdma_uar_map { | |
| 107 | + unsigned long pfn; | |
| 108 | + void __iomem *map; | |
| 109 | + int index; | |
| 110 | +}; | |
| 111 | + | |
| 112 | +struct pvrdma_uar_table { | |
| 113 | + struct pvrdma_id_table tbl; | |
| 114 | + int size; | |
| 115 | +}; | |
| 116 | + | |
| 117 | +struct pvrdma_ucontext { | |
| 118 | + struct ib_ucontext ibucontext; | |
| 119 | + struct pvrdma_dev *dev; | |
| 120 | + struct pvrdma_uar_map uar; | |
| 121 | + u64 ctx_handle; | |
| 122 | +}; | |
| 123 | + | |
| 124 | +struct pvrdma_pd { | |
| 125 | + struct ib_pd ibpd; | |
| 126 | + u32 pdn; | |
| 127 | + u32 pd_handle; | |
| 128 | + int privileged; | |
| 129 | +}; | |
| 130 | + | |
| 131 | +struct pvrdma_mr { | |
| 132 | + u32 mr_handle; | |
| 133 | + u64 iova; | |
| 134 | + u64 size; | |
| 135 | +}; | |
| 136 | + | |
| 137 | +struct pvrdma_user_mr { | |
| 138 | + struct ib_mr ibmr; | |
| 139 | + struct ib_umem *umem; | |
| 140 | + struct pvrdma_mr mmr; | |
| 141 | + struct pvrdma_page_dir pdir; | |
| 142 | + u64 *pages; | |
| 143 | + u32 npages; | |
| 144 | + u32 max_pages; | |
| 145 | + u32 page_shift; | |
| 146 | +}; | |
| 147 | + | |
| 148 | +struct pvrdma_wq { | |
| 149 | + struct pvrdma_ring *ring; | |
| 150 | + spinlock_t lock; /* Work queue lock. */ | |
| 151 | + int wqe_cnt; | |
| 152 | + int wqe_size; | |
| 153 | + int max_sg; | |
| 154 | + int offset; | |
| 155 | +}; | |
| 156 | + | |
| 157 | +struct pvrdma_ah { | |
| 158 | + struct ib_ah ibah; | |
| 159 | + struct pvrdma_av av; | |
| 160 | +}; | |
| 161 | + | |
| 162 | +struct pvrdma_qp { | |
| 163 | + struct ib_qp ibqp; | |
| 164 | + u32 qp_handle; | |
| 165 | + u32 qkey; | |
| 166 | + struct pvrdma_wq sq; | |
| 167 | + struct pvrdma_wq rq; | |
| 168 | + struct ib_umem *rumem; | |
| 169 | + struct ib_umem *sumem; | |
| 170 | + struct pvrdma_page_dir pdir; | |
| 171 | + int npages; | |
| 172 | + int npages_send; | |
| 173 | + int npages_recv; | |
| 174 | + u32 flags; | |
| 175 | + u8 port; | |
| 176 | + u8 state; | |
| 177 | + bool is_kernel; | |
| 178 | + struct mutex mutex; /* QP state mutex. */ | |
| 179 | + atomic_t refcnt; | |
| 180 | + wait_queue_head_t wait; | |
| 181 | +}; | |
| 182 | + | |
| 183 | +struct pvrdma_dev { | |
| 184 | + /* PCI device-related information. */ | |
| 185 | + struct ib_device ib_dev; | |
| 186 | + struct pci_dev *pdev; | |
| 187 | + void __iomem *regs; | |
| 188 | + struct pvrdma_device_shared_region *dsr; /* Shared region pointer */ | |
| 189 | + dma_addr_t dsrbase; /* Shared region base address */ | |
| 190 | + void *cmd_slot; | |
| 191 | + void *resp_slot; | |
| 192 | + unsigned long flags; | |
| 193 | + struct list_head device_link; | |
| 194 | + | |
| 195 | + /* Locking and interrupt information. */ | |
| 196 | + spinlock_t cmd_lock; /* Command lock. */ | |
| 197 | + struct semaphore cmd_sema; | |
| 198 | + struct completion cmd_done; | |
| 199 | + struct { | |
| 200 | + enum pvrdma_intr_type type; /* Intr type */ | |
| 201 | + struct msix_entry msix_entry[PVRDMA_MAX_INTERRUPTS]; | |
| 202 | + irq_handler_t handler[PVRDMA_MAX_INTERRUPTS]; | |
| 203 | + u8 enabled[PVRDMA_MAX_INTERRUPTS]; | |
| 204 | + u8 size; | |
| 205 | + } intr; | |
| 206 | + | |
| 207 | + /* RDMA-related device information. */ | |
| 208 | + union ib_gid *sgid_tbl; | |
| 209 | + struct pvrdma_ring_state *async_ring_state; | |
| 210 | + struct pvrdma_page_dir async_pdir; | |
| 211 | + struct pvrdma_ring_state *cq_ring_state; | |
| 212 | + struct pvrdma_page_dir cq_pdir; | |
| 213 | + struct pvrdma_cq **cq_tbl; | |
| 214 | + spinlock_t cq_tbl_lock; | |
| 215 | + struct pvrdma_qp **qp_tbl; | |
| 216 | + spinlock_t qp_tbl_lock; | |
| 217 | + struct pvrdma_uar_table uar_table; | |
| 218 | + struct pvrdma_uar_map driver_uar; | |
| 219 | + __be64 sys_image_guid; | |
| 220 | + spinlock_t desc_lock; /* Device modification lock. */ | |
| 221 | + u32 port_cap_mask; | |
| 222 | + struct mutex port_mutex; /* Port modification mutex. */ | |
| 223 | + bool ib_active; | |
| 224 | + atomic_t num_qps; | |
| 225 | + atomic_t num_cqs; | |
| 226 | + atomic_t num_pds; | |
| 227 | + atomic_t num_ahs; | |
| 228 | + | |
| 229 | + /* Network device information. */ | |
| 230 | + struct net_device *netdev; | |
| 231 | + struct notifier_block nb_netdev; | |
| 232 | +}; | |
| 233 | + | |
| 234 | +struct pvrdma_netdevice_work { | |
| 235 | + struct work_struct work; | |
| 236 | + struct net_device *event_netdev; | |
| 237 | + unsigned long event; | |
| 238 | +}; | |
| 239 | + | |
| 240 | +static inline struct pvrdma_dev *to_vdev(struct ib_device *ibdev) | |
| 241 | +{ | |
| 242 | + return container_of(ibdev, struct pvrdma_dev, ib_dev); | |
| 243 | +} | |
| 244 | + | |
| 245 | +static inline struct | |
| 246 | +pvrdma_ucontext *to_vucontext(struct ib_ucontext *ibucontext) | |
| 247 | +{ | |
| 248 | + return container_of(ibucontext, struct pvrdma_ucontext, ibucontext); | |
| 249 | +} | |
| 250 | + | |
| 251 | +static inline struct pvrdma_pd *to_vpd(struct ib_pd *ibpd) | |
| 252 | +{ | |
| 253 | + return container_of(ibpd, struct pvrdma_pd, ibpd); | |
| 254 | +} | |
| 255 | + | |
| 256 | +static inline struct pvrdma_cq *to_vcq(struct ib_cq *ibcq) | |
| 257 | +{ | |
| 258 | + return container_of(ibcq, struct pvrdma_cq, ibcq); | |
| 259 | +} | |
| 260 | + | |
| 261 | +static inline struct pvrdma_user_mr *to_vmr(struct ib_mr *ibmr) | |
| 262 | +{ | |
| 263 | + return container_of(ibmr, struct pvrdma_user_mr, ibmr); | |
| 264 | +} | |
| 265 | + | |
| 266 | +static inline struct pvrdma_qp *to_vqp(struct ib_qp *ibqp) | |
| 267 | +{ | |
| 268 | + return container_of(ibqp, struct pvrdma_qp, ibqp); | |
| 269 | +} | |
| 270 | + | |
| 271 | +static inline struct pvrdma_ah *to_vah(struct ib_ah *ibah) | |
| 272 | +{ | |
| 273 | + return container_of(ibah, struct pvrdma_ah, ibah); | |
| 274 | +} | |
| 275 | + | |
| 276 | +static inline void pvrdma_write_reg(struct pvrdma_dev *dev, u32 reg, u32 val) | |
| 277 | +{ | |
| 278 | + writel(cpu_to_le32(val), dev->regs + reg); | |
| 279 | +} | |
| 280 | + | |
| 281 | +static inline u32 pvrdma_read_reg(struct pvrdma_dev *dev, u32 reg) | |
| 282 | +{ | |
| 283 | + return le32_to_cpu(readl(dev->regs + reg)); | |
| 284 | +} | |
| 285 | + | |
| 286 | +static inline void pvrdma_write_uar_cq(struct pvrdma_dev *dev, u32 val) | |
| 287 | +{ | |
| 288 | + writel(cpu_to_le32(val), dev->driver_uar.map + PVRDMA_UAR_CQ_OFFSET); | |
| 289 | +} | |
| 290 | + | |
| 291 | +static inline void pvrdma_write_uar_qp(struct pvrdma_dev *dev, u32 val) | |
| 292 | +{ | |
| 293 | + writel(cpu_to_le32(val), dev->driver_uar.map + PVRDMA_UAR_QP_OFFSET); | |
| 294 | +} | |
| 295 | + | |
| 296 | +static inline void *pvrdma_page_dir_get_ptr(struct pvrdma_page_dir *pdir, | |
| 297 | + u64 offset) | |
| 298 | +{ | |
| 299 | + return pdir->pages[offset / PAGE_SIZE] + (offset % PAGE_SIZE); | |
| 300 | +} | |
| 301 | + | |
| 302 | +static inline enum pvrdma_mtu ib_mtu_to_pvrdma(enum ib_mtu mtu) | |
| 303 | +{ | |
| 304 | + return (enum pvrdma_mtu)mtu; | |
| 305 | +} | |
| 306 | + | |
| 307 | +static inline enum ib_mtu pvrdma_mtu_to_ib(enum pvrdma_mtu mtu) | |
| 308 | +{ | |
| 309 | + return (enum ib_mtu)mtu; | |
| 310 | +} | |
| 311 | + | |
| 312 | +static inline enum pvrdma_port_state ib_port_state_to_pvrdma( | |
| 313 | + enum ib_port_state state) | |
| 314 | +{ | |
| 315 | + return (enum pvrdma_port_state)state; | |
| 316 | +} | |
| 317 | + | |
| 318 | +static inline enum ib_port_state pvrdma_port_state_to_ib( | |
| 319 | + enum pvrdma_port_state state) | |
| 320 | +{ | |
| 321 | + return (enum ib_port_state)state; | |
| 322 | +} | |
| 323 | + | |
| 324 | +static inline int ib_port_cap_flags_to_pvrdma(int flags) | |
| 325 | +{ | |
| 326 | + return flags & PVRDMA_MASK(PVRDMA_PORT_CAP_FLAGS_MAX); | |
| 327 | +} | |
| 328 | + | |
| 329 | +static inline int pvrdma_port_cap_flags_to_ib(int flags) | |
| 330 | +{ | |
| 331 | + return flags; | |
| 332 | +} | |
| 333 | + | |
| 334 | +static inline enum pvrdma_port_width ib_port_width_to_pvrdma( | |
| 335 | + enum ib_port_width width) | |
| 336 | +{ | |
| 337 | + return (enum pvrdma_port_width)width; | |
| 338 | +} | |
| 339 | + | |
| 340 | +static inline enum ib_port_width pvrdma_port_width_to_ib( | |
| 341 | + enum pvrdma_port_width width) | |
| 342 | +{ | |
| 343 | + return (enum ib_port_width)width; | |
| 344 | +} | |
| 345 | + | |
| 346 | +static inline enum pvrdma_port_speed ib_port_speed_to_pvrdma( | |
| 347 | + enum ib_port_speed speed) | |
| 348 | +{ | |
| 349 | + return (enum pvrdma_port_speed)speed; | |
| 350 | +} | |
| 351 | + | |
| 352 | +static inline enum ib_port_speed pvrdma_port_speed_to_ib( | |
| 353 | + enum pvrdma_port_speed speed) | |
| 354 | +{ | |
| 355 | + return (enum ib_port_speed)speed; | |
| 356 | +} | |
| 357 | + | |
| 358 | +static inline int pvrdma_qp_attr_mask_to_ib(int attr_mask) | |
| 359 | +{ | |
| 360 | + return attr_mask; | |
| 361 | +} | |
| 362 | + | |
| 363 | +static inline int ib_qp_attr_mask_to_pvrdma(int attr_mask) | |
| 364 | +{ | |
| 365 | + return attr_mask & PVRDMA_MASK(PVRDMA_QP_ATTR_MASK_MAX); | |
| 366 | +} | |
| 367 | + | |
| 368 | +static inline enum pvrdma_mig_state ib_mig_state_to_pvrdma( | |
| 369 | + enum ib_mig_state state) | |
| 370 | +{ | |
| 371 | + return (enum pvrdma_mig_state)state; | |
| 372 | +} | |
| 373 | + | |
| 374 | +static inline enum ib_mig_state pvrdma_mig_state_to_ib( | |
| 375 | + enum pvrdma_mig_state state) | |
| 376 | +{ | |
| 377 | + return (enum ib_mig_state)state; | |
| 378 | +} | |
| 379 | + | |
| 380 | +static inline int ib_access_flags_to_pvrdma(int flags) | |
| 381 | +{ | |
| 382 | + return flags; | |
| 383 | +} | |
| 384 | + | |
| 385 | +static inline int pvrdma_access_flags_to_ib(int flags) | |
| 386 | +{ | |
| 387 | + return flags & PVRDMA_MASK(PVRDMA_ACCESS_FLAGS_MAX); | |
| 388 | +} | |
| 389 | + | |
| 390 | +static inline enum pvrdma_qp_type ib_qp_type_to_pvrdma(enum ib_qp_type type) | |
| 391 | +{ | |
| 392 | + return (enum pvrdma_qp_type)type; | |
| 393 | +} | |
| 394 | + | |
| 395 | +static inline enum ib_qp_type pvrdma_qp_type_to_ib(enum pvrdma_qp_type type) | |
| 396 | +{ | |
| 397 | + return (enum ib_qp_type)type; | |
| 398 | +} | |
| 399 | + | |
| 400 | +static inline enum pvrdma_qp_state ib_qp_state_to_pvrdma(enum ib_qp_state state) | |
| 401 | +{ | |
| 402 | + return (enum pvrdma_qp_state)state; | |
| 403 | +} | |
| 404 | + | |
| 405 | +static inline enum ib_qp_state pvrdma_qp_state_to_ib(enum pvrdma_qp_state state) | |
| 406 | +{ | |
| 407 | + return (enum ib_qp_state)state; | |
| 408 | +} | |
| 409 | + | |
| 410 | +static inline enum pvrdma_wr_opcode ib_wr_opcode_to_pvrdma(enum ib_wr_opcode op) | |
| 411 | +{ | |
| 412 | + return (enum pvrdma_wr_opcode)op; | |
| 413 | +} | |
| 414 | + | |
| 415 | +static inline enum ib_wc_status pvrdma_wc_status_to_ib( | |
| 416 | + enum pvrdma_wc_status status) | |
| 417 | +{ | |
| 418 | + return (enum ib_wc_status)status; | |
| 419 | +} | |
| 420 | + | |
| 421 | +static inline int pvrdma_wc_opcode_to_ib(int opcode) | |
| 422 | +{ | |
| 423 | + return opcode; | |
| 424 | +} | |
| 425 | + | |
| 426 | +static inline int pvrdma_wc_flags_to_ib(int flags) | |
| 427 | +{ | |
| 428 | + return flags; | |
| 429 | +} | |
| 430 | + | |
| 431 | +static inline int ib_send_flags_to_pvrdma(int flags) | |
| 432 | +{ | |
| 433 | + return flags & PVRDMA_MASK(PVRDMA_SEND_FLAGS_MAX); | |
| 434 | +} | |
| 435 | + | |
| 436 | +void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, | |
| 437 | + const struct pvrdma_qp_cap *src); | |
| 438 | +void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, | |
| 439 | + const struct ib_qp_cap *src); | |
| 440 | +void pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src); | |
| 441 | +void ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src); | |
| 442 | +void pvrdma_global_route_to_ib(struct ib_global_route *dst, | |
| 443 | + const struct pvrdma_global_route *src); | |
| 444 | +void ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, | |
| 445 | + const struct ib_global_route *src); | |
| 446 | +void pvrdma_ah_attr_to_ib(struct ib_ah_attr *dst, | |
| 447 | + const struct pvrdma_ah_attr *src); | |
| 448 | +void ib_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, | |
| 449 | + const struct ib_ah_attr *src); | |
| 450 | + | |
| 451 | +int pvrdma_uar_table_init(struct pvrdma_dev *dev); | |
| 452 | +void pvrdma_uar_table_cleanup(struct pvrdma_dev *dev); | |
| 453 | + | |
| 454 | +int pvrdma_uar_alloc(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar); | |
| 455 | +void pvrdma_uar_free(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar); | |
| 456 | + | |
| 457 | +void _pvrdma_flush_cqe(struct pvrdma_qp *qp, struct pvrdma_cq *cq); | |
| 458 | + | |
| 459 | +int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, | |
| 460 | + u64 npages, bool alloc_pages); | |
| 461 | +void pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, | |
| 462 | + struct pvrdma_page_dir *pdir); | |
| 463 | +int pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, | |
| 464 | + dma_addr_t daddr); | |
| 465 | +int pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, | |
| 466 | + struct ib_umem *umem, u64 offset); | |
| 467 | +dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx); | |
| 468 | +int pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, | |
| 469 | + u64 *page_list, int num_pages); | |
| 470 | + | |
| 471 | +int pvrdma_cmd_post(struct pvrdma_dev *dev, union pvrdma_cmd_req *req, | |
| 472 | + union pvrdma_cmd_resp *rsp, unsigned resp_code); | |
| 473 | + | |
| 474 | +#endif /* __PVRDMA_H__ */ | |
| @@ -0,0 +1,119 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <linux/list.h> | |
| 47 | + | |
| 48 | +#include "pvrdma.h" | |
| 49 | + | |
| 50 | +#define PVRDMA_CMD_TIMEOUT 10000 /* ms */ | |
| 51 | + | |
| 52 | +static inline int pvrdma_cmd_recv(struct pvrdma_dev *dev, | |
| 53 | + union pvrdma_cmd_resp *resp, | |
| 54 | + unsigned resp_code) | |
| 55 | +{ | |
| 56 | + int err; | |
| 57 | + | |
| 58 | + dev_dbg(&dev->pdev->dev, "receive response from device\n"); | |
| 59 | + | |
| 60 | + err = wait_for_completion_interruptible_timeout(&dev->cmd_done, | |
| 61 | + msecs_to_jiffies(PVRDMA_CMD_TIMEOUT)); | |
| 62 | + if (err == 0 || err == -ERESTARTSYS) { | |
| 63 | + dev_warn(&dev->pdev->dev, | |
| 64 | + "completion timeout or interrupted\n"); | |
| 65 | + return -ETIMEDOUT; | |
| 66 | + } | |
| 67 | + | |
| 68 | + spin_lock(&dev->cmd_lock); | |
| 69 | + memcpy(resp, dev->resp_slot, sizeof(*resp)); | |
| 70 | + spin_unlock(&dev->cmd_lock); | |
| 71 | + | |
| 72 | + if (resp->hdr.ack != resp_code) { | |
| 73 | + dev_warn(&dev->pdev->dev, | |
| 74 | + "unknown response %#x expected %#x\n", | |
| 75 | + resp->hdr.ack, resp_code); | |
| 76 | + return -EFAULT; | |
| 77 | + } | |
| 78 | + | |
| 79 | + return 0; | |
| 80 | +} | |
| 81 | + | |
| 82 | +int | |
| 83 | +pvrdma_cmd_post(struct pvrdma_dev *dev, union pvrdma_cmd_req *req, | |
| 84 | + union pvrdma_cmd_resp *resp, unsigned resp_code) | |
| 85 | +{ | |
| 86 | + int err; | |
| 87 | + | |
| 88 | + dev_dbg(&dev->pdev->dev, "post request to device\n"); | |
| 89 | + | |
| 90 | + /* Serializiation */ | |
| 91 | + down(&dev->cmd_sema); | |
| 92 | + | |
| 93 | + BUILD_BUG_ON(sizeof(union pvrdma_cmd_req) != | |
| 94 | + sizeof(struct pvrdma_cmd_modify_qp)); | |
| 95 | + | |
| 96 | + spin_lock(&dev->cmd_lock); | |
| 97 | + memcpy(dev->cmd_slot, req, sizeof(*req)); | |
| 98 | + spin_unlock(&dev->cmd_lock); | |
| 99 | + | |
| 100 | + init_completion(&dev->cmd_done); | |
| 101 | + pvrdma_write_reg(dev, PVRDMA_REG_REQUEST, 0); | |
| 102 | + | |
| 103 | + /* Make sure the request is written before reading status. */ | |
| 104 | + mb(); | |
| 105 | + | |
| 106 | + err = pvrdma_read_reg(dev, PVRDMA_REG_ERR); | |
| 107 | + if (err == 0) { | |
| 108 | + if (resp != NULL) | |
| 109 | + err = pvrdma_cmd_recv(dev, resp, resp_code); | |
| 110 | + } else { | |
| 111 | + dev_warn(&dev->pdev->dev, | |
| 112 | + "failed to write request error reg: %d\n", err); | |
| 113 | + err = -EFAULT; | |
| 114 | + } | |
| 115 | + | |
| 116 | + up(&dev->cmd_sema); | |
| 117 | + | |
| 118 | + return err; | |
| 119 | +} | |
| @@ -0,0 +1,425 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <asm/page.h> | |
| 47 | +#include <linux/io.h> | |
| 48 | +#include <linux/wait.h> | |
| 49 | +#include <rdma/ib_addr.h> | |
| 50 | +#include <rdma/ib_smi.h> | |
| 51 | +#include <rdma/ib_user_verbs.h> | |
| 52 | + | |
| 53 | +#include "pvrdma.h" | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * pvrdma_req_notify_cq - request notification for a completion queue | |
| 57 | + * @ibcq: the completion queue | |
| 58 | + * @notify_flags: notification flags | |
| 59 | + * | |
| 60 | + * @return: 0 for success. | |
| 61 | + */ | |
| 62 | +int pvrdma_req_notify_cq(struct ib_cq *ibcq, | |
| 63 | + enum ib_cq_notify_flags notify_flags) | |
| 64 | +{ | |
| 65 | + struct pvrdma_dev *dev = to_vdev(ibcq->device); | |
| 66 | + struct pvrdma_cq *cq = to_vcq(ibcq); | |
| 67 | + u32 val = cq->cq_handle; | |
| 68 | + | |
| 69 | + val |= (notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? | |
| 70 | + PVRDMA_UAR_CQ_ARM_SOL : PVRDMA_UAR_CQ_ARM; | |
| 71 | + | |
| 72 | + pvrdma_write_uar_cq(dev, val); | |
| 73 | + | |
| 74 | + return 0; | |
| 75 | +} | |
| 76 | + | |
| 77 | +/** | |
| 78 | + * pvrdma_create_cq - create completion queue | |
| 79 | + * @ibdev: the device | |
| 80 | + * @attr: completion queue attributes | |
| 81 | + * @context: user context | |
| 82 | + * @udata: user data | |
| 83 | + * | |
| 84 | + * @return: ib_cq completion queue pointer on success, | |
| 85 | + * otherwise returns negative errno. | |
| 86 | + */ | |
| 87 | +struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, | |
| 88 | + const struct ib_cq_init_attr *attr, | |
| 89 | + struct ib_ucontext *context, | |
| 90 | + struct ib_udata *udata) | |
| 91 | +{ | |
| 92 | + int entries = attr->cqe; | |
| 93 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 94 | + struct pvrdma_cq *cq; | |
| 95 | + int ret; | |
| 96 | + int npages; | |
| 97 | + unsigned long flags; | |
| 98 | + union pvrdma_cmd_req req; | |
| 99 | + union pvrdma_cmd_resp rsp; | |
| 100 | + struct pvrdma_cmd_create_cq *cmd = &req.create_cq; | |
| 101 | + struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp; | |
| 102 | + struct pvrdma_create_cq ucmd; | |
| 103 | + | |
| 104 | + BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64); | |
| 105 | + | |
| 106 | + entries = roundup_pow_of_two(entries); | |
| 107 | + if (entries < 1 || entries > dev->dsr->caps.max_cqe) | |
| 108 | + return ERR_PTR(-EINVAL); | |
| 109 | + | |
| 110 | + if (!atomic_add_unless(&dev->num_cqs, 1, dev->dsr->caps.max_cq)) | |
| 111 | + return ERR_PTR(-ENOMEM); | |
| 112 | + | |
| 113 | + cq = kzalloc(sizeof(*cq), GFP_KERNEL); | |
| 114 | + if (!cq) { | |
| 115 | + atomic_dec(&dev->num_cqs); | |
| 116 | + return ERR_PTR(-ENOMEM); | |
| 117 | + } | |
| 118 | + | |
| 119 | + cq->ibcq.cqe = entries; | |
| 120 | + | |
| 121 | + if (context) { | |
| 122 | + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { | |
| 123 | + ret = -EFAULT; | |
| 124 | + goto err_cq; | |
| 125 | + } | |
| 126 | + | |
| 127 | + cq->umem = ib_umem_get(context, ucmd.buf_addr, ucmd.buf_size, | |
| 128 | + IB_ACCESS_LOCAL_WRITE, 1); | |
| 129 | + if (IS_ERR(cq->umem)) { | |
| 130 | + ret = PTR_ERR(cq->umem); | |
| 131 | + goto err_cq; | |
| 132 | + } | |
| 133 | + | |
| 134 | + npages = ib_umem_page_count(cq->umem); | |
| 135 | + } else { | |
| 136 | + cq->is_kernel = true; | |
| 137 | + | |
| 138 | + /* One extra page for shared ring state */ | |
| 139 | + npages = 1 + (entries * sizeof(struct pvrdma_cqe) + | |
| 140 | + PAGE_SIZE - 1) / PAGE_SIZE; | |
| 141 | + | |
| 142 | + /* Skip header page. */ | |
| 143 | + cq->offset = PAGE_SIZE; | |
| 144 | + } | |
| 145 | + | |
| 146 | + if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) { | |
| 147 | + dev_warn(&dev->pdev->dev, | |
| 148 | + "overflow pages in completion queue\n"); | |
| 149 | + ret = -EINVAL; | |
| 150 | + goto err_umem; | |
| 151 | + } | |
| 152 | + | |
| 153 | + ret = pvrdma_page_dir_init(dev, &cq->pdir, npages, cq->is_kernel); | |
| 154 | + if (ret) { | |
| 155 | + dev_warn(&dev->pdev->dev, | |
| 156 | + "could not allocate page directory\n"); | |
| 157 | + goto err_umem; | |
| 158 | + } | |
| 159 | + | |
| 160 | + /* Ring state is always the first page. Set in library for user cq. */ | |
| 161 | + if (cq->is_kernel) | |
| 162 | + cq->ring_state = cq->pdir.pages[0]; | |
| 163 | + else | |
| 164 | + pvrdma_page_dir_insert_umem(&cq->pdir, cq->umem, 0); | |
| 165 | + | |
| 166 | + atomic_set(&cq->refcnt, 1); | |
| 167 | + init_waitqueue_head(&cq->wait); | |
| 168 | + spin_lock_init(&cq->cq_lock); | |
| 169 | + | |
| 170 | + memset(cmd, 0, sizeof(*cmd)); | |
| 171 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_CQ; | |
| 172 | + cmd->nchunks = npages; | |
| 173 | + cmd->ctx_handle = (context) ? | |
| 174 | + (u64)to_vucontext(context)->ctx_handle : 0; | |
| 175 | + cmd->cqe = entries; | |
| 176 | + cmd->pdir_dma = cq->pdir.dir_dma; | |
| 177 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_CQ_RESP); | |
| 178 | + if (ret < 0) { | |
| 179 | + dev_warn(&dev->pdev->dev, | |
| 180 | + "could not create completion queue, error: %d\n", ret); | |
| 181 | + goto err_page_dir; | |
| 182 | + } | |
| 183 | + | |
| 184 | + cq->ibcq.cqe = resp->cqe; | |
| 185 | + cq->cq_handle = resp->cq_handle; | |
| 186 | + spin_lock_irqsave(&dev->cq_tbl_lock, flags); | |
| 187 | + dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq; | |
| 188 | + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); | |
| 189 | + | |
| 190 | + if (context) { | |
| 191 | + cq->uar = &(to_vucontext(context)->uar); | |
| 192 | + | |
| 193 | + /* Copy udata back. */ | |
| 194 | + if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) { | |
| 195 | + dev_warn(&dev->pdev->dev, | |
| 196 | + "failed to copy back udata\n"); | |
| 197 | + pvrdma_destroy_cq(&cq->ibcq); | |
| 198 | + return ERR_PTR(-EINVAL); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + return &cq->ibcq; | |
| 203 | + | |
| 204 | +err_page_dir: | |
| 205 | + pvrdma_page_dir_cleanup(dev, &cq->pdir); | |
| 206 | +err_umem: | |
| 207 | + if (context) | |
| 208 | + ib_umem_release(cq->umem); | |
| 209 | +err_cq: | |
| 210 | + atomic_dec(&dev->num_cqs); | |
| 211 | + kfree(cq); | |
| 212 | + | |
| 213 | + return ERR_PTR(ret); | |
| 214 | +} | |
| 215 | + | |
| 216 | +static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq) | |
| 217 | +{ | |
| 218 | + atomic_dec(&cq->refcnt); | |
| 219 | + wait_event(cq->wait, !atomic_read(&cq->refcnt)); | |
| 220 | + | |
| 221 | + if (!cq->is_kernel) | |
| 222 | + ib_umem_release(cq->umem); | |
| 223 | + | |
| 224 | + pvrdma_page_dir_cleanup(dev, &cq->pdir); | |
| 225 | + kfree(cq); | |
| 226 | +} | |
| 227 | + | |
| 228 | +/** | |
| 229 | + * pvrdma_destroy_cq - destroy completion queue | |
| 230 | + * @cq: the completion queue to destroy. | |
| 231 | + * | |
| 232 | + * @return: 0 for success. | |
| 233 | + */ | |
| 234 | +int pvrdma_destroy_cq(struct ib_cq *cq) | |
| 235 | +{ | |
| 236 | + struct pvrdma_cq *vcq = to_vcq(cq); | |
| 237 | + union pvrdma_cmd_req req; | |
| 238 | + struct pvrdma_cmd_destroy_cq *cmd = &req.destroy_cq; | |
| 239 | + struct pvrdma_dev *dev = to_vdev(cq->device); | |
| 240 | + unsigned long flags; | |
| 241 | + int ret; | |
| 242 | + | |
| 243 | + memset(cmd, 0, sizeof(*cmd)); | |
| 244 | + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_CQ; | |
| 245 | + cmd->cq_handle = vcq->cq_handle; | |
| 246 | + | |
| 247 | + ret = pvrdma_cmd_post(dev, &req, NULL, 0); | |
| 248 | + if (ret < 0) | |
| 249 | + dev_warn(&dev->pdev->dev, | |
| 250 | + "could not destroy completion queue, error: %d\n", | |
| 251 | + ret); | |
| 252 | + | |
| 253 | + /* free cq's resources */ | |
| 254 | + spin_lock_irqsave(&dev->cq_tbl_lock, flags); | |
| 255 | + dev->cq_tbl[vcq->cq_handle] = NULL; | |
| 256 | + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); | |
| 257 | + | |
| 258 | + pvrdma_free_cq(dev, vcq); | |
| 259 | + atomic_dec(&dev->num_cqs); | |
| 260 | + | |
| 261 | + return ret; | |
| 262 | +} | |
| 263 | + | |
| 264 | +/** | |
| 265 | + * pvrdma_modify_cq - modify the CQ moderation parameters | |
| 266 | + * @ibcq: the CQ to modify | |
| 267 | + * @cq_count: number of CQEs that will trigger an event | |
| 268 | + * @cq_period: max period of time in usec before triggering an event | |
| 269 | + * | |
| 270 | + * @return: -EOPNOTSUPP as CQ resize is not supported. | |
| 271 | + */ | |
| 272 | +int pvrdma_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) | |
| 273 | +{ | |
| 274 | + return -EOPNOTSUPP; | |
| 275 | +} | |
| 276 | + | |
| 277 | +static inline struct pvrdma_cqe *get_cqe(struct pvrdma_cq *cq, int i) | |
| 278 | +{ | |
| 279 | + return (struct pvrdma_cqe *)pvrdma_page_dir_get_ptr( | |
| 280 | + &cq->pdir, | |
| 281 | + cq->offset + | |
| 282 | + sizeof(struct pvrdma_cqe) * i); | |
| 283 | +} | |
| 284 | + | |
| 285 | +void _pvrdma_flush_cqe(struct pvrdma_qp *qp, struct pvrdma_cq *cq) | |
| 286 | +{ | |
| 287 | + int head; | |
| 288 | + int has_data; | |
| 289 | + | |
| 290 | + if (!cq->is_kernel) | |
| 291 | + return; | |
| 292 | + | |
| 293 | + /* Lock held */ | |
| 294 | + has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, | |
| 295 | + cq->ibcq.cqe, &head); | |
| 296 | + if (unlikely(has_data > 0)) { | |
| 297 | + int items; | |
| 298 | + int curr; | |
| 299 | + int tail = pvrdma_idx(&cq->ring_state->rx.prod_tail, | |
| 300 | + cq->ibcq.cqe); | |
| 301 | + struct pvrdma_cqe *cqe; | |
| 302 | + struct pvrdma_cqe *curr_cqe; | |
| 303 | + | |
| 304 | + items = (tail > head) ? (tail - head) : | |
| 305 | + (cq->ibcq.cqe - head + tail); | |
| 306 | + curr = --tail; | |
| 307 | + while (items-- > 0) { | |
| 308 | + if (curr < 0) | |
| 309 | + curr = cq->ibcq.cqe - 1; | |
| 310 | + if (tail < 0) | |
| 311 | + tail = cq->ibcq.cqe - 1; | |
| 312 | + curr_cqe = get_cqe(cq, curr); | |
| 313 | + if ((curr_cqe->qp & 0xFFFF) != qp->qp_handle) { | |
| 314 | + if (curr != tail) { | |
| 315 | + cqe = get_cqe(cq, tail); | |
| 316 | + *cqe = *curr_cqe; | |
| 317 | + } | |
| 318 | + tail--; | |
| 319 | + } else { | |
| 320 | + pvrdma_idx_ring_inc( | |
| 321 | + &cq->ring_state->rx.cons_head, | |
| 322 | + cq->ibcq.cqe); | |
| 323 | + } | |
| 324 | + curr--; | |
| 325 | + } | |
| 326 | + } | |
| 327 | +} | |
| 328 | + | |
| 329 | +static int pvrdma_poll_one(struct pvrdma_cq *cq, struct pvrdma_qp **cur_qp, | |
| 330 | + struct ib_wc *wc) | |
| 331 | +{ | |
| 332 | + struct pvrdma_dev *dev = to_vdev(cq->ibcq.device); | |
| 333 | + int has_data; | |
| 334 | + unsigned int head; | |
| 335 | + bool tried = false; | |
| 336 | + struct pvrdma_cqe *cqe; | |
| 337 | + | |
| 338 | +retry: | |
| 339 | + has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, | |
| 340 | + cq->ibcq.cqe, &head); | |
| 341 | + if (has_data == 0) { | |
| 342 | + if (tried) | |
| 343 | + return -EAGAIN; | |
| 344 | + | |
| 345 | + pvrdma_write_uar_cq(dev, cq->cq_handle | PVRDMA_UAR_CQ_POLL); | |
| 346 | + | |
| 347 | + tried = true; | |
| 348 | + goto retry; | |
| 349 | + } else if (has_data == PVRDMA_INVALID_IDX) { | |
| 350 | + dev_err(&dev->pdev->dev, "CQ ring state invalid\n"); | |
| 351 | + return -EAGAIN; | |
| 352 | + } | |
| 353 | + | |
| 354 | + cqe = get_cqe(cq, head); | |
| 355 | + | |
| 356 | + /* Ensure cqe is valid. */ | |
| 357 | + rmb(); | |
| 358 | + if (dev->qp_tbl[cqe->qp & 0xffff]) | |
| 359 | + *cur_qp = (struct pvrdma_qp *)dev->qp_tbl[cqe->qp & 0xffff]; | |
| 360 | + else | |
| 361 | + return -EAGAIN; | |
| 362 | + | |
| 363 | + wc->opcode = pvrdma_wc_opcode_to_ib(cqe->opcode); | |
| 364 | + wc->status = pvrdma_wc_status_to_ib(cqe->status); | |
| 365 | + wc->wr_id = cqe->wr_id; | |
| 366 | + wc->qp = &(*cur_qp)->ibqp; | |
| 367 | + wc->byte_len = cqe->byte_len; | |
| 368 | + wc->ex.imm_data = cqe->imm_data; | |
| 369 | + wc->src_qp = cqe->src_qp; | |
| 370 | + wc->wc_flags = pvrdma_wc_flags_to_ib(cqe->wc_flags); | |
| 371 | + wc->pkey_index = cqe->pkey_index; | |
| 372 | + wc->slid = cqe->slid; | |
| 373 | + wc->sl = cqe->sl; | |
| 374 | + wc->dlid_path_bits = cqe->dlid_path_bits; | |
| 375 | + wc->port_num = cqe->port_num; | |
| 376 | + wc->vendor_err = 0; | |
| 377 | + | |
| 378 | + /* Update shared ring state */ | |
| 379 | + pvrdma_idx_ring_inc(&cq->ring_state->rx.cons_head, cq->ibcq.cqe); | |
| 380 | + | |
| 381 | + return 0; | |
| 382 | +} | |
| 383 | + | |
| 384 | +/** | |
| 385 | + * pvrdma_poll_cq - poll for work completion queue entries | |
| 386 | + * @ibcq: completion queue | |
| 387 | + * @num_entries: the maximum number of entries | |
| 388 | + * @entry: pointer to work completion array | |
| 389 | + * | |
| 390 | + * @return: number of polled completion entries | |
| 391 | + */ | |
| 392 | +int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) | |
| 393 | +{ | |
| 394 | + struct pvrdma_cq *cq = to_vcq(ibcq); | |
| 395 | + struct pvrdma_qp *cur_qp = NULL; | |
| 396 | + unsigned long flags; | |
| 397 | + int npolled; | |
| 398 | + | |
| 399 | + if (num_entries < 1 || wc == NULL) | |
| 400 | + return 0; | |
| 401 | + | |
| 402 | + spin_lock_irqsave(&cq->cq_lock, flags); | |
| 403 | + for (npolled = 0; npolled < num_entries; ++npolled) { | |
| 404 | + if (pvrdma_poll_one(cq, &cur_qp, wc + npolled)) | |
| 405 | + break; | |
| 406 | + } | |
| 407 | + | |
| 408 | + spin_unlock_irqrestore(&cq->cq_lock, flags); | |
| 409 | + | |
| 410 | + /* Ensure we do not return errors from poll_cq */ | |
| 411 | + return npolled; | |
| 412 | +} | |
| 413 | + | |
| 414 | +/** | |
| 415 | + * pvrdma_resize_cq - resize CQ | |
| 416 | + * @ibcq: the completion queue | |
| 417 | + * @entries: CQ entries | |
| 418 | + * @udata: user data | |
| 419 | + * | |
| 420 | + * @return: -EOPNOTSUPP as CQ resize is not supported. | |
| 421 | + */ | |
| 422 | +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) | |
| 423 | +{ | |
| 424 | + return -EOPNOTSUPP; | |
| 425 | +} | |
| @@ -0,0 +1,586 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#ifndef __PVRDMA_DEV_API_H__ | |
| 47 | +#define __PVRDMA_DEV_API_H__ | |
| 48 | + | |
| 49 | +#include <linux/types.h> | |
| 50 | + | |
| 51 | +#include "pvrdma_verbs.h" | |
| 52 | + | |
| 53 | +#define PVRDMA_VERSION 17 | |
| 54 | +#define PVRDMA_BOARD_ID 1 | |
| 55 | +#define PVRDMA_REV_ID 1 | |
| 56 | + | |
| 57 | +/* | |
| 58 | + * Masks and accessors for page directory, which is a two-level lookup: | |
| 59 | + * page directory -> page table -> page. Only one directory for now, but we | |
| 60 | + * could expand that easily. 9 bits for tables, 9 bits for pages, gives one | |
| 61 | + * gigabyte for memory regions and so forth. | |
| 62 | + */ | |
| 63 | + | |
| 64 | +#define PVRDMA_PDIR_SHIFT 18 | |
| 65 | +#define PVRDMA_PTABLE_SHIFT 9 | |
| 66 | +#define PVRDMA_PAGE_DIR_DIR(x) (((x) >> PVRDMA_PDIR_SHIFT) & 0x1) | |
| 67 | +#define PVRDMA_PAGE_DIR_TABLE(x) (((x) >> PVRDMA_PTABLE_SHIFT) & 0x1ff) | |
| 68 | +#define PVRDMA_PAGE_DIR_PAGE(x) ((x) & 0x1ff) | |
| 69 | +#define PVRDMA_PAGE_DIR_MAX_PAGES (1 * 512 * 512) | |
| 70 | +#define PVRDMA_MAX_FAST_REG_PAGES 128 | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * Max MSI-X vectors. | |
| 74 | + */ | |
| 75 | + | |
| 76 | +#define PVRDMA_MAX_INTERRUPTS 3 | |
| 77 | + | |
| 78 | +/* Register offsets within PCI resource on BAR1. */ | |
| 79 | +#define PVRDMA_REG_VERSION 0x00 /* R: Version of device. */ | |
| 80 | +#define PVRDMA_REG_DSRLOW 0x04 /* W: Device shared region low PA. */ | |
| 81 | +#define PVRDMA_REG_DSRHIGH 0x08 /* W: Device shared region high PA. */ | |
| 82 | +#define PVRDMA_REG_CTL 0x0c /* W: PVRDMA_DEVICE_CTL */ | |
| 83 | +#define PVRDMA_REG_REQUEST 0x10 /* W: Indicate device request. */ | |
| 84 | +#define PVRDMA_REG_ERR 0x14 /* R: Device error. */ | |
| 85 | +#define PVRDMA_REG_ICR 0x18 /* R: Interrupt cause. */ | |
| 86 | +#define PVRDMA_REG_IMR 0x1c /* R/W: Interrupt mask. */ | |
| 87 | +#define PVRDMA_REG_MACL 0x20 /* R/W: MAC address low. */ | |
| 88 | +#define PVRDMA_REG_MACH 0x24 /* R/W: MAC address high. */ | |
| 89 | + | |
| 90 | +/* Object flags. */ | |
| 91 | +#define PVRDMA_CQ_FLAG_ARMED_SOL BIT(0) /* Armed for solicited-only. */ | |
| 92 | +#define PVRDMA_CQ_FLAG_ARMED BIT(1) /* Armed. */ | |
| 93 | +#define PVRDMA_MR_FLAG_DMA BIT(0) /* DMA region. */ | |
| 94 | +#define PVRDMA_MR_FLAG_FRMR BIT(1) /* Fast reg memory region. */ | |
| 95 | + | |
| 96 | +/* | |
| 97 | + * Atomic operation capability (masked versions are extended atomic | |
| 98 | + * operations. | |
| 99 | + */ | |
| 100 | + | |
| 101 | +#define PVRDMA_ATOMIC_OP_COMP_SWAP BIT(0) /* Compare and swap. */ | |
| 102 | +#define PVRDMA_ATOMIC_OP_FETCH_ADD BIT(1) /* Fetch and add. */ | |
| 103 | +#define PVRDMA_ATOMIC_OP_MASK_COMP_SWAP BIT(2) /* Masked compare and swap. */ | |
| 104 | +#define PVRDMA_ATOMIC_OP_MASK_FETCH_ADD BIT(3) /* Masked fetch and add. */ | |
| 105 | + | |
| 106 | +/* | |
| 107 | + * Base Memory Management Extension flags to support Fast Reg Memory Regions | |
| 108 | + * and Fast Reg Work Requests. Each flag represents a verb operation and we | |
| 109 | + * must support all of them to qualify for the BMME device cap. | |
| 110 | + */ | |
| 111 | + | |
| 112 | +#define PVRDMA_BMME_FLAG_LOCAL_INV BIT(0) /* Local Invalidate. */ | |
| 113 | +#define PVRDMA_BMME_FLAG_REMOTE_INV BIT(1) /* Remote Invalidate. */ | |
| 114 | +#define PVRDMA_BMME_FLAG_FAST_REG_WR BIT(2) /* Fast Reg Work Request. */ | |
| 115 | + | |
| 116 | +/* | |
| 117 | + * GID types. The interpretation of the gid_types bit field in the device | |
| 118 | + * capabilities will depend on the device mode. For now, the device only | |
| 119 | + * supports RoCE as mode, so only the different GID types for RoCE are | |
| 120 | + * defined. | |
| 121 | + */ | |
| 122 | + | |
| 123 | +#define PVRDMA_GID_TYPE_FLAG_ROCE_V1 BIT(0) | |
| 124 | +#define PVRDMA_GID_TYPE_FLAG_ROCE_V2 BIT(1) | |
| 125 | + | |
| 126 | +enum pvrdma_pci_resource { | |
| 127 | + PVRDMA_PCI_RESOURCE_MSIX, /* BAR0: MSI-X, MMIO. */ | |
| 128 | + PVRDMA_PCI_RESOURCE_REG, /* BAR1: Registers, MMIO. */ | |
| 129 | + PVRDMA_PCI_RESOURCE_UAR, /* BAR2: UAR pages, MMIO, 64-bit. */ | |
| 130 | + PVRDMA_PCI_RESOURCE_LAST, /* Last. */ | |
| 131 | +}; | |
| 132 | + | |
| 133 | +enum pvrdma_device_ctl { | |
| 134 | + PVRDMA_DEVICE_CTL_ACTIVATE, /* Activate device. */ | |
| 135 | + PVRDMA_DEVICE_CTL_QUIESCE, /* Quiesce device. */ | |
| 136 | + PVRDMA_DEVICE_CTL_RESET, /* Reset device. */ | |
| 137 | +}; | |
| 138 | + | |
| 139 | +enum pvrdma_intr_vector { | |
| 140 | + PVRDMA_INTR_VECTOR_RESPONSE, /* Command response. */ | |
| 141 | + PVRDMA_INTR_VECTOR_ASYNC, /* Async events. */ | |
| 142 | + PVRDMA_INTR_VECTOR_CQ, /* CQ notification. */ | |
| 143 | + /* Additional CQ notification vectors. */ | |
| 144 | +}; | |
| 145 | + | |
| 146 | +enum pvrdma_intr_cause { | |
| 147 | + PVRDMA_INTR_CAUSE_RESPONSE = (1 << PVRDMA_INTR_VECTOR_RESPONSE), | |
| 148 | + PVRDMA_INTR_CAUSE_ASYNC = (1 << PVRDMA_INTR_VECTOR_ASYNC), | |
| 149 | + PVRDMA_INTR_CAUSE_CQ = (1 << PVRDMA_INTR_VECTOR_CQ), | |
| 150 | +}; | |
| 151 | + | |
| 152 | +enum pvrdma_intr_type { | |
| 153 | + PVRDMA_INTR_TYPE_INTX, /* Legacy. */ | |
| 154 | + PVRDMA_INTR_TYPE_MSI, /* MSI. */ | |
| 155 | + PVRDMA_INTR_TYPE_MSIX, /* MSI-X. */ | |
| 156 | +}; | |
| 157 | + | |
| 158 | +enum pvrdma_gos_bits { | |
| 159 | + PVRDMA_GOS_BITS_UNK, /* Unknown. */ | |
| 160 | + PVRDMA_GOS_BITS_32, /* 32-bit. */ | |
| 161 | + PVRDMA_GOS_BITS_64, /* 64-bit. */ | |
| 162 | +}; | |
| 163 | + | |
| 164 | +enum pvrdma_gos_type { | |
| 165 | + PVRDMA_GOS_TYPE_UNK, /* Unknown. */ | |
| 166 | + PVRDMA_GOS_TYPE_LINUX, /* Linux. */ | |
| 167 | +}; | |
| 168 | + | |
| 169 | +enum pvrdma_device_mode { | |
| 170 | + PVRDMA_DEVICE_MODE_ROCE, /* RoCE. */ | |
| 171 | + PVRDMA_DEVICE_MODE_IWARP, /* iWarp. */ | |
| 172 | + PVRDMA_DEVICE_MODE_IB, /* InfiniBand. */ | |
| 173 | +}; | |
| 174 | + | |
| 175 | +struct pvrdma_gos_info { | |
| 176 | + u32 gos_bits:2; /* W: PVRDMA_GOS_BITS_ */ | |
| 177 | + u32 gos_type:4; /* W: PVRDMA_GOS_TYPE_ */ | |
| 178 | + u32 gos_ver:16; /* W: Guest OS version. */ | |
| 179 | + u32 gos_misc:10; /* W: Other. */ | |
| 180 | + u32 pad; /* Pad to 8-byte alignment. */ | |
| 181 | +}; | |
| 182 | + | |
| 183 | +struct pvrdma_device_caps { | |
| 184 | + u64 fw_ver; /* R: Query device. */ | |
| 185 | + __be64 node_guid; | |
| 186 | + __be64 sys_image_guid; | |
| 187 | + u64 max_mr_size; | |
| 188 | + u64 page_size_cap; | |
| 189 | + u64 atomic_arg_sizes; /* EX verbs. */ | |
| 190 | + u32 ex_comp_mask; /* EX verbs. */ | |
| 191 | + u32 device_cap_flags2; /* EX verbs. */ | |
| 192 | + u32 max_fa_bit_boundary; /* EX verbs. */ | |
| 193 | + u32 log_max_atomic_inline_arg; /* EX verbs. */ | |
| 194 | + u32 vendor_id; | |
| 195 | + u32 vendor_part_id; | |
| 196 | + u32 hw_ver; | |
| 197 | + u32 max_qp; | |
| 198 | + u32 max_qp_wr; | |
| 199 | + u32 device_cap_flags; | |
| 200 | + u32 max_sge; | |
| 201 | + u32 max_sge_rd; | |
| 202 | + u32 max_cq; | |
| 203 | + u32 max_cqe; | |
| 204 | + u32 max_mr; | |
| 205 | + u32 max_pd; | |
| 206 | + u32 max_qp_rd_atom; | |
| 207 | + u32 max_ee_rd_atom; | |
| 208 | + u32 max_res_rd_atom; | |
| 209 | + u32 max_qp_init_rd_atom; | |
| 210 | + u32 max_ee_init_rd_atom; | |
| 211 | + u32 max_ee; | |
| 212 | + u32 max_rdd; | |
| 213 | + u32 max_mw; | |
| 214 | + u32 max_raw_ipv6_qp; | |
| 215 | + u32 max_raw_ethy_qp; | |
| 216 | + u32 max_mcast_grp; | |
| 217 | + u32 max_mcast_qp_attach; | |
| 218 | + u32 max_total_mcast_qp_attach; | |
| 219 | + u32 max_ah; | |
| 220 | + u32 max_fmr; | |
| 221 | + u32 max_map_per_fmr; | |
| 222 | + u32 max_srq; | |
| 223 | + u32 max_srq_wr; | |
| 224 | + u32 max_srq_sge; | |
| 225 | + u32 max_uar; | |
| 226 | + u32 gid_tbl_len; | |
| 227 | + u16 max_pkeys; | |
| 228 | + u8 local_ca_ack_delay; | |
| 229 | + u8 phys_port_cnt; | |
| 230 | + u8 mode; /* PVRDMA_DEVICE_MODE_ */ | |
| 231 | + u8 atomic_ops; /* PVRDMA_ATOMIC_OP_* bits */ | |
| 232 | + u8 bmme_flags; /* FRWR Mem Mgmt Extensions */ | |
| 233 | + u8 gid_types; /* PVRDMA_GID_TYPE_FLAG_ */ | |
| 234 | + u8 reserved[4]; | |
| 235 | +}; | |
| 236 | + | |
| 237 | +struct pvrdma_ring_page_info { | |
| 238 | + u32 num_pages; /* Num pages incl. header. */ | |
| 239 | + u32 reserved; /* Reserved. */ | |
| 240 | + u64 pdir_dma; /* Page directory PA. */ | |
| 241 | +}; | |
| 242 | + | |
| 243 | +#pragma pack(push, 1) | |
| 244 | + | |
| 245 | +struct pvrdma_device_shared_region { | |
| 246 | + u32 driver_version; /* W: Driver version. */ | |
| 247 | + u32 pad; /* Pad to 8-byte align. */ | |
| 248 | + struct pvrdma_gos_info gos_info; /* W: Guest OS information. */ | |
| 249 | + u64 cmd_slot_dma; /* W: Command slot address. */ | |
| 250 | + u64 resp_slot_dma; /* W: Response slot address. */ | |
| 251 | + struct pvrdma_ring_page_info async_ring_pages; | |
| 252 | + /* W: Async ring page info. */ | |
| 253 | + struct pvrdma_ring_page_info cq_ring_pages; | |
| 254 | + /* W: CQ ring page info. */ | |
| 255 | + u32 uar_pfn; /* W: UAR pageframe. */ | |
| 256 | + u32 pad2; /* Pad to 8-byte align. */ | |
| 257 | + struct pvrdma_device_caps caps; /* R: Device capabilities. */ | |
| 258 | +}; | |
| 259 | + | |
| 260 | +#pragma pack(pop) | |
| 261 | + | |
| 262 | +/* Event types. Currently a 1:1 mapping with enum ib_event. */ | |
| 263 | +enum pvrdma_eqe_type { | |
| 264 | + PVRDMA_EVENT_CQ_ERR, | |
| 265 | + PVRDMA_EVENT_QP_FATAL, | |
| 266 | + PVRDMA_EVENT_QP_REQ_ERR, | |
| 267 | + PVRDMA_EVENT_QP_ACCESS_ERR, | |
| 268 | + PVRDMA_EVENT_COMM_EST, | |
| 269 | + PVRDMA_EVENT_SQ_DRAINED, | |
| 270 | + PVRDMA_EVENT_PATH_MIG, | |
| 271 | + PVRDMA_EVENT_PATH_MIG_ERR, | |
| 272 | + PVRDMA_EVENT_DEVICE_FATAL, | |
| 273 | + PVRDMA_EVENT_PORT_ACTIVE, | |
| 274 | + PVRDMA_EVENT_PORT_ERR, | |
| 275 | + PVRDMA_EVENT_LID_CHANGE, | |
| 276 | + PVRDMA_EVENT_PKEY_CHANGE, | |
| 277 | + PVRDMA_EVENT_SM_CHANGE, | |
| 278 | + PVRDMA_EVENT_SRQ_ERR, | |
| 279 | + PVRDMA_EVENT_SRQ_LIMIT_REACHED, | |
| 280 | + PVRDMA_EVENT_QP_LAST_WQE_REACHED, | |
| 281 | + PVRDMA_EVENT_CLIENT_REREGISTER, | |
| 282 | + PVRDMA_EVENT_GID_CHANGE, | |
| 283 | +}; | |
| 284 | + | |
| 285 | +/* Event queue element. */ | |
| 286 | +struct pvrdma_eqe { | |
| 287 | + u32 type; /* Event type. */ | |
| 288 | + u32 info; /* Handle, other. */ | |
| 289 | +}; | |
| 290 | + | |
| 291 | +/* CQ notification queue element. */ | |
| 292 | +struct pvrdma_cqne { | |
| 293 | + u32 info; /* Handle */ | |
| 294 | +}; | |
| 295 | + | |
| 296 | +enum { | |
| 297 | + PVRDMA_CMD_FIRST, | |
| 298 | + PVRDMA_CMD_QUERY_PORT = PVRDMA_CMD_FIRST, | |
| 299 | + PVRDMA_CMD_QUERY_PKEY, | |
| 300 | + PVRDMA_CMD_CREATE_PD, | |
| 301 | + PVRDMA_CMD_DESTROY_PD, | |
| 302 | + PVRDMA_CMD_CREATE_MR, | |
| 303 | + PVRDMA_CMD_DESTROY_MR, | |
| 304 | + PVRDMA_CMD_CREATE_CQ, | |
| 305 | + PVRDMA_CMD_RESIZE_CQ, | |
| 306 | + PVRDMA_CMD_DESTROY_CQ, | |
| 307 | + PVRDMA_CMD_CREATE_QP, | |
| 308 | + PVRDMA_CMD_MODIFY_QP, | |
| 309 | + PVRDMA_CMD_QUERY_QP, | |
| 310 | + PVRDMA_CMD_DESTROY_QP, | |
| 311 | + PVRDMA_CMD_CREATE_UC, | |
| 312 | + PVRDMA_CMD_DESTROY_UC, | |
| 313 | + PVRDMA_CMD_CREATE_BIND, | |
| 314 | + PVRDMA_CMD_DESTROY_BIND, | |
| 315 | + PVRDMA_CMD_MAX, | |
| 316 | +}; | |
| 317 | + | |
| 318 | +enum { | |
| 319 | + PVRDMA_CMD_FIRST_RESP = (1 << 31), | |
| 320 | + PVRDMA_CMD_QUERY_PORT_RESP = PVRDMA_CMD_FIRST_RESP, | |
| 321 | + PVRDMA_CMD_QUERY_PKEY_RESP, | |
| 322 | + PVRDMA_CMD_CREATE_PD_RESP, | |
| 323 | + PVRDMA_CMD_DESTROY_PD_RESP_NOOP, | |
| 324 | + PVRDMA_CMD_CREATE_MR_RESP, | |
| 325 | + PVRDMA_CMD_DESTROY_MR_RESP_NOOP, | |
| 326 | + PVRDMA_CMD_CREATE_CQ_RESP, | |
| 327 | + PVRDMA_CMD_RESIZE_CQ_RESP, | |
| 328 | + PVRDMA_CMD_DESTROY_CQ_RESP_NOOP, | |
| 329 | + PVRDMA_CMD_CREATE_QP_RESP, | |
| 330 | + PVRDMA_CMD_MODIFY_QP_RESP, | |
| 331 | + PVRDMA_CMD_QUERY_QP_RESP, | |
| 332 | + PVRDMA_CMD_DESTROY_QP_RESP, | |
| 333 | + PVRDMA_CMD_CREATE_UC_RESP, | |
| 334 | + PVRDMA_CMD_DESTROY_UC_RESP_NOOP, | |
| 335 | + PVRDMA_CMD_CREATE_BIND_RESP_NOOP, | |
| 336 | + PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, | |
| 337 | + PVRDMA_CMD_MAX_RESP, | |
| 338 | +}; | |
| 339 | + | |
| 340 | +struct pvrdma_cmd_hdr { | |
| 341 | + u64 response; /* Key for response lookup. */ | |
| 342 | + u32 cmd; /* PVRDMA_CMD_ */ | |
| 343 | + u32 reserved; /* Reserved. */ | |
| 344 | +}; | |
| 345 | + | |
| 346 | +struct pvrdma_cmd_resp_hdr { | |
| 347 | + u64 response; /* From cmd hdr. */ | |
| 348 | + u32 ack; /* PVRDMA_CMD_XXX_RESP */ | |
| 349 | + u8 err; /* Error. */ | |
| 350 | + u8 reserved[3]; /* Reserved. */ | |
| 351 | +}; | |
| 352 | + | |
| 353 | +struct pvrdma_cmd_query_port { | |
| 354 | + struct pvrdma_cmd_hdr hdr; | |
| 355 | + u8 port_num; | |
| 356 | + u8 reserved[7]; | |
| 357 | +}; | |
| 358 | + | |
| 359 | +struct pvrdma_cmd_query_port_resp { | |
| 360 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 361 | + struct pvrdma_port_attr attrs; | |
| 362 | +}; | |
| 363 | + | |
| 364 | +struct pvrdma_cmd_query_pkey { | |
| 365 | + struct pvrdma_cmd_hdr hdr; | |
| 366 | + u8 port_num; | |
| 367 | + u8 index; | |
| 368 | + u8 reserved[6]; | |
| 369 | +}; | |
| 370 | + | |
| 371 | +struct pvrdma_cmd_query_pkey_resp { | |
| 372 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 373 | + u16 pkey; | |
| 374 | + u8 reserved[6]; | |
| 375 | +}; | |
| 376 | + | |
| 377 | +struct pvrdma_cmd_create_uc { | |
| 378 | + struct pvrdma_cmd_hdr hdr; | |
| 379 | + u32 pfn; /* UAR page frame number */ | |
| 380 | + u8 reserved[4]; | |
| 381 | +}; | |
| 382 | + | |
| 383 | +struct pvrdma_cmd_create_uc_resp { | |
| 384 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 385 | + u32 ctx_handle; | |
| 386 | + u8 reserved[4]; | |
| 387 | +}; | |
| 388 | + | |
| 389 | +struct pvrdma_cmd_destroy_uc { | |
| 390 | + struct pvrdma_cmd_hdr hdr; | |
| 391 | + u32 ctx_handle; | |
| 392 | + u8 reserved[4]; | |
| 393 | +}; | |
| 394 | + | |
| 395 | +struct pvrdma_cmd_create_pd { | |
| 396 | + struct pvrdma_cmd_hdr hdr; | |
| 397 | + u32 ctx_handle; | |
| 398 | + u8 reserved[4]; | |
| 399 | +}; | |
| 400 | + | |
| 401 | +struct pvrdma_cmd_create_pd_resp { | |
| 402 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 403 | + u32 pd_handle; | |
| 404 | + u8 reserved[4]; | |
| 405 | +}; | |
| 406 | + | |
| 407 | +struct pvrdma_cmd_destroy_pd { | |
| 408 | + struct pvrdma_cmd_hdr hdr; | |
| 409 | + u32 pd_handle; | |
| 410 | + u8 reserved[4]; | |
| 411 | +}; | |
| 412 | + | |
| 413 | +struct pvrdma_cmd_create_mr { | |
| 414 | + struct pvrdma_cmd_hdr hdr; | |
| 415 | + u64 start; | |
| 416 | + u64 length; | |
| 417 | + u64 pdir_dma; | |
| 418 | + u32 pd_handle; | |
| 419 | + u32 access_flags; | |
| 420 | + u32 flags; | |
| 421 | + u32 nchunks; | |
| 422 | +}; | |
| 423 | + | |
| 424 | +struct pvrdma_cmd_create_mr_resp { | |
| 425 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 426 | + u32 mr_handle; | |
| 427 | + u32 lkey; | |
| 428 | + u32 rkey; | |
| 429 | + u8 reserved[4]; | |
| 430 | +}; | |
| 431 | + | |
| 432 | +struct pvrdma_cmd_destroy_mr { | |
| 433 | + struct pvrdma_cmd_hdr hdr; | |
| 434 | + u32 mr_handle; | |
| 435 | + u8 reserved[4]; | |
| 436 | +}; | |
| 437 | + | |
| 438 | +struct pvrdma_cmd_create_cq { | |
| 439 | + struct pvrdma_cmd_hdr hdr; | |
| 440 | + u64 pdir_dma; | |
| 441 | + u32 ctx_handle; | |
| 442 | + u32 cqe; | |
| 443 | + u32 nchunks; | |
| 444 | + u8 reserved[4]; | |
| 445 | +}; | |
| 446 | + | |
| 447 | +struct pvrdma_cmd_create_cq_resp { | |
| 448 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 449 | + u32 cq_handle; | |
| 450 | + u32 cqe; | |
| 451 | +}; | |
| 452 | + | |
| 453 | +struct pvrdma_cmd_resize_cq { | |
| 454 | + struct pvrdma_cmd_hdr hdr; | |
| 455 | + u32 cq_handle; | |
| 456 | + u32 cqe; | |
| 457 | +}; | |
| 458 | + | |
| 459 | +struct pvrdma_cmd_resize_cq_resp { | |
| 460 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 461 | + u32 cqe; | |
| 462 | + u8 reserved[4]; | |
| 463 | +}; | |
| 464 | + | |
| 465 | +struct pvrdma_cmd_destroy_cq { | |
| 466 | + struct pvrdma_cmd_hdr hdr; | |
| 467 | + u32 cq_handle; | |
| 468 | + u8 reserved[4]; | |
| 469 | +}; | |
| 470 | + | |
| 471 | +struct pvrdma_cmd_create_qp { | |
| 472 | + struct pvrdma_cmd_hdr hdr; | |
| 473 | + u64 pdir_dma; | |
| 474 | + u32 pd_handle; | |
| 475 | + u32 send_cq_handle; | |
| 476 | + u32 recv_cq_handle; | |
| 477 | + u32 srq_handle; | |
| 478 | + u32 max_send_wr; | |
| 479 | + u32 max_recv_wr; | |
| 480 | + u32 max_send_sge; | |
| 481 | + u32 max_recv_sge; | |
| 482 | + u32 max_inline_data; | |
| 483 | + u32 lkey; | |
| 484 | + u32 access_flags; | |
| 485 | + u16 total_chunks; | |
| 486 | + u16 send_chunks; | |
| 487 | + u16 max_atomic_arg; | |
| 488 | + u8 sq_sig_all; | |
| 489 | + u8 qp_type; | |
| 490 | + u8 is_srq; | |
| 491 | + u8 reserved[3]; | |
| 492 | +}; | |
| 493 | + | |
| 494 | +struct pvrdma_cmd_create_qp_resp { | |
| 495 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 496 | + u32 qpn; | |
| 497 | + u32 max_send_wr; | |
| 498 | + u32 max_recv_wr; | |
| 499 | + u32 max_send_sge; | |
| 500 | + u32 max_recv_sge; | |
| 501 | + u32 max_inline_data; | |
| 502 | +}; | |
| 503 | + | |
| 504 | +struct pvrdma_cmd_modify_qp { | |
| 505 | + struct pvrdma_cmd_hdr hdr; | |
| 506 | + u32 qp_handle; | |
| 507 | + u32 attr_mask; | |
| 508 | + struct pvrdma_qp_attr attrs; | |
| 509 | +}; | |
| 510 | + | |
| 511 | +struct pvrdma_cmd_query_qp { | |
| 512 | + struct pvrdma_cmd_hdr hdr; | |
| 513 | + u32 qp_handle; | |
| 514 | + u32 attr_mask; | |
| 515 | +}; | |
| 516 | + | |
| 517 | +struct pvrdma_cmd_query_qp_resp { | |
| 518 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 519 | + struct pvrdma_qp_attr attrs; | |
| 520 | +}; | |
| 521 | + | |
| 522 | +struct pvrdma_cmd_destroy_qp { | |
| 523 | + struct pvrdma_cmd_hdr hdr; | |
| 524 | + u32 qp_handle; | |
| 525 | + u8 reserved[4]; | |
| 526 | +}; | |
| 527 | + | |
| 528 | +struct pvrdma_cmd_destroy_qp_resp { | |
| 529 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 530 | + u32 events_reported; | |
| 531 | + u8 reserved[4]; | |
| 532 | +}; | |
| 533 | + | |
| 534 | +struct pvrdma_cmd_create_bind { | |
| 535 | + struct pvrdma_cmd_hdr hdr; | |
| 536 | + u32 mtu; | |
| 537 | + u32 vlan; | |
| 538 | + u32 index; | |
| 539 | + u8 new_gid[16]; | |
| 540 | + u8 gid_type; | |
| 541 | + u8 reserved[3]; | |
| 542 | +}; | |
| 543 | + | |
| 544 | +struct pvrdma_cmd_destroy_bind { | |
| 545 | + struct pvrdma_cmd_hdr hdr; | |
| 546 | + u32 index; | |
| 547 | + u8 dest_gid[16]; | |
| 548 | + u8 reserved[4]; | |
| 549 | +}; | |
| 550 | + | |
| 551 | +union pvrdma_cmd_req { | |
| 552 | + struct pvrdma_cmd_hdr hdr; | |
| 553 | + struct pvrdma_cmd_query_port query_port; | |
| 554 | + struct pvrdma_cmd_query_pkey query_pkey; | |
| 555 | + struct pvrdma_cmd_create_uc create_uc; | |
| 556 | + struct pvrdma_cmd_destroy_uc destroy_uc; | |
| 557 | + struct pvrdma_cmd_create_pd create_pd; | |
| 558 | + struct pvrdma_cmd_destroy_pd destroy_pd; | |
| 559 | + struct pvrdma_cmd_create_mr create_mr; | |
| 560 | + struct pvrdma_cmd_destroy_mr destroy_mr; | |
| 561 | + struct pvrdma_cmd_create_cq create_cq; | |
| 562 | + struct pvrdma_cmd_resize_cq resize_cq; | |
| 563 | + struct pvrdma_cmd_destroy_cq destroy_cq; | |
| 564 | + struct pvrdma_cmd_create_qp create_qp; | |
| 565 | + struct pvrdma_cmd_modify_qp modify_qp; | |
| 566 | + struct pvrdma_cmd_query_qp query_qp; | |
| 567 | + struct pvrdma_cmd_destroy_qp destroy_qp; | |
| 568 | + struct pvrdma_cmd_create_bind create_bind; | |
| 569 | + struct pvrdma_cmd_destroy_bind destroy_bind; | |
| 570 | +}; | |
| 571 | + | |
| 572 | +union pvrdma_cmd_resp { | |
| 573 | + struct pvrdma_cmd_resp_hdr hdr; | |
| 574 | + struct pvrdma_cmd_query_port_resp query_port_resp; | |
| 575 | + struct pvrdma_cmd_query_pkey_resp query_pkey_resp; | |
| 576 | + struct pvrdma_cmd_create_uc_resp create_uc_resp; | |
| 577 | + struct pvrdma_cmd_create_pd_resp create_pd_resp; | |
| 578 | + struct pvrdma_cmd_create_mr_resp create_mr_resp; | |
| 579 | + struct pvrdma_cmd_create_cq_resp create_cq_resp; | |
| 580 | + struct pvrdma_cmd_resize_cq_resp resize_cq_resp; | |
| 581 | + struct pvrdma_cmd_create_qp_resp create_qp_resp; | |
| 582 | + struct pvrdma_cmd_query_qp_resp query_qp_resp; | |
| 583 | + struct pvrdma_cmd_destroy_qp_resp destroy_qp_resp; | |
| 584 | +}; | |
| 585 | + | |
| 586 | +#endif /* __PVRDMA_DEV_API_H__ */ | |
| @@ -0,0 +1,127 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <linux/bitmap.h> | |
| 47 | +#include <linux/errno.h> | |
| 48 | +#include <linux/slab.h> | |
| 49 | + | |
| 50 | +#include "pvrdma.h" | |
| 51 | + | |
| 52 | +int pvrdma_uar_table_init(struct pvrdma_dev *dev) | |
| 53 | +{ | |
| 54 | + u32 num = dev->dsr->caps.max_uar; | |
| 55 | + u32 mask = num - 1; | |
| 56 | + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; | |
| 57 | + | |
| 58 | + if (!is_power_of_2(num)) | |
| 59 | + return -EINVAL; | |
| 60 | + | |
| 61 | + tbl->last = 0; | |
| 62 | + tbl->top = 0; | |
| 63 | + tbl->max = num; | |
| 64 | + tbl->mask = mask; | |
| 65 | + spin_lock_init(&tbl->lock); | |
| 66 | + tbl->table = kcalloc(BITS_TO_LONGS(num), sizeof(long), GFP_KERNEL); | |
| 67 | + if (!tbl->table) | |
| 68 | + return -ENOMEM; | |
| 69 | + | |
| 70 | + /* 0th UAR is taken by the device. */ | |
| 71 | + set_bit(0, tbl->table); | |
| 72 | + | |
| 73 | + return 0; | |
| 74 | +} | |
| 75 | + | |
| 76 | +void pvrdma_uar_table_cleanup(struct pvrdma_dev *dev) | |
| 77 | +{ | |
| 78 | + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; | |
| 79 | + | |
| 80 | + kfree(tbl->table); | |
| 81 | +} | |
| 82 | + | |
| 83 | +int pvrdma_uar_alloc(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) | |
| 84 | +{ | |
| 85 | + struct pvrdma_id_table *tbl; | |
| 86 | + unsigned long flags; | |
| 87 | + u32 obj; | |
| 88 | + | |
| 89 | + tbl = &dev->uar_table.tbl; | |
| 90 | + | |
| 91 | + spin_lock_irqsave(&tbl->lock, flags); | |
| 92 | + obj = find_next_zero_bit(tbl->table, tbl->max, tbl->last); | |
| 93 | + if (obj >= tbl->max) { | |
| 94 | + tbl->top = (tbl->top + tbl->max) & tbl->mask; | |
| 95 | + obj = find_first_zero_bit(tbl->table, tbl->max); | |
| 96 | + } | |
| 97 | + | |
| 98 | + if (obj >= tbl->max) { | |
| 99 | + spin_unlock_irqrestore(&tbl->lock, flags); | |
| 100 | + return -ENOMEM; | |
| 101 | + } | |
| 102 | + | |
| 103 | + set_bit(obj, tbl->table); | |
| 104 | + obj |= tbl->top; | |
| 105 | + | |
| 106 | + spin_unlock_irqrestore(&tbl->lock, flags); | |
| 107 | + | |
| 108 | + uar->index = obj; | |
| 109 | + uar->pfn = (pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >> | |
| 110 | + PAGE_SHIFT) + uar->index; | |
| 111 | + | |
| 112 | + return 0; | |
| 113 | +} | |
| 114 | + | |
| 115 | +void pvrdma_uar_free(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) | |
| 116 | +{ | |
| 117 | + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; | |
| 118 | + unsigned long flags; | |
| 119 | + u32 obj; | |
| 120 | + | |
| 121 | + obj = uar->index & (tbl->max - 1); | |
| 122 | + spin_lock_irqsave(&tbl->lock, flags); | |
| 123 | + clear_bit(obj, tbl->table); | |
| 124 | + tbl->last = min(tbl->last, obj); | |
| 125 | + tbl->top = (tbl->top + tbl->max) & tbl->mask; | |
| 126 | + spin_unlock_irqrestore(&tbl->lock, flags); | |
| 127 | +} | |
| @@ -0,0 +1,1211 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <linux/errno.h> | |
| 47 | +#include <linux/inetdevice.h> | |
| 48 | +#include <linux/init.h> | |
| 49 | +#include <linux/module.h> | |
| 50 | +#include <linux/slab.h> | |
| 51 | +#include <rdma/ib_addr.h> | |
| 52 | +#include <rdma/ib_smi.h> | |
| 53 | +#include <rdma/ib_user_verbs.h> | |
| 54 | +#include <net/addrconf.h> | |
| 55 | + | |
| 56 | +#include "pvrdma.h" | |
| 57 | + | |
| 58 | +#define DRV_NAME "vmw_pvrdma" | |
| 59 | +#define DRV_VERSION "1.0.0.0-k" | |
| 60 | + | |
| 61 | +static DEFINE_MUTEX(pvrdma_device_list_lock); | |
| 62 | +static LIST_HEAD(pvrdma_device_list); | |
| 63 | +static struct workqueue_struct *event_wq; | |
| 64 | + | |
| 65 | +static int pvrdma_add_gid(struct ib_device *ibdev, | |
| 66 | + u8 port_num, | |
| 67 | + unsigned int index, | |
| 68 | + const union ib_gid *gid, | |
| 69 | + const struct ib_gid_attr *attr, | |
| 70 | + void **context); | |
| 71 | +static int pvrdma_del_gid(struct ib_device *ibdev, | |
| 72 | + u8 port_num, | |
| 73 | + unsigned int index, | |
| 74 | + void **context); | |
| 75 | + | |
| 76 | + | |
| 77 | +static ssize_t show_hca(struct device *device, struct device_attribute *attr, | |
| 78 | + char *buf) | |
| 79 | +{ | |
| 80 | + return sprintf(buf, "VMW_PVRDMA-%s\n", DRV_VERSION); | |
| 81 | +} | |
| 82 | + | |
| 83 | +static ssize_t show_rev(struct device *device, struct device_attribute *attr, | |
| 84 | + char *buf) | |
| 85 | +{ | |
| 86 | + return sprintf(buf, "%d\n", PVRDMA_REV_ID); | |
| 87 | +} | |
| 88 | + | |
| 89 | +static ssize_t show_board(struct device *device, struct device_attribute *attr, | |
| 90 | + char *buf) | |
| 91 | +{ | |
| 92 | + return sprintf(buf, "%d\n", PVRDMA_BOARD_ID); | |
| 93 | +} | |
| 94 | + | |
| 95 | +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); | |
| 96 | +static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); | |
| 97 | +static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); | |
| 98 | + | |
| 99 | +static struct device_attribute *pvrdma_class_attributes[] = { | |
| 100 | + &dev_attr_hw_rev, | |
| 101 | + &dev_attr_hca_type, | |
| 102 | + &dev_attr_board_id | |
| 103 | +}; | |
| 104 | + | |
| 105 | +static void pvrdma_get_fw_ver_str(struct ib_device *device, char *str, | |
| 106 | + size_t str_len) | |
| 107 | +{ | |
| 108 | + struct pvrdma_dev *dev = | |
| 109 | + container_of(device, struct pvrdma_dev, ib_dev); | |
| 110 | + snprintf(str, str_len, "%d.%d.%d\n", | |
| 111 | + (int) (dev->dsr->caps.fw_ver >> 32), | |
| 112 | + (int) (dev->dsr->caps.fw_ver >> 16) & 0xffff, | |
| 113 | + (int) dev->dsr->caps.fw_ver & 0xffff); | |
| 114 | +} | |
| 115 | + | |
| 116 | +static int pvrdma_init_device(struct pvrdma_dev *dev) | |
| 117 | +{ | |
| 118 | + /* Initialize some device related stuff */ | |
| 119 | + spin_lock_init(&dev->cmd_lock); | |
| 120 | + sema_init(&dev->cmd_sema, 1); | |
| 121 | + atomic_set(&dev->num_qps, 0); | |
| 122 | + atomic_set(&dev->num_cqs, 0); | |
| 123 | + atomic_set(&dev->num_pds, 0); | |
| 124 | + atomic_set(&dev->num_ahs, 0); | |
| 125 | + | |
| 126 | + return 0; | |
| 127 | +} | |
| 128 | + | |
| 129 | +static int pvrdma_port_immutable(struct ib_device *ibdev, u8 port_num, | |
| 130 | + struct ib_port_immutable *immutable) | |
| 131 | +{ | |
| 132 | + struct ib_port_attr attr; | |
| 133 | + int err; | |
| 134 | + | |
| 135 | + err = pvrdma_query_port(ibdev, port_num, &attr); | |
| 136 | + if (err) | |
| 137 | + return err; | |
| 138 | + | |
| 139 | + immutable->pkey_tbl_len = attr.pkey_tbl_len; | |
| 140 | + immutable->gid_tbl_len = attr.gid_tbl_len; | |
| 141 | + immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE; | |
| 142 | + immutable->max_mad_size = IB_MGMT_MAD_SIZE; | |
| 143 | + return 0; | |
| 144 | +} | |
| 145 | + | |
| 146 | +static struct net_device *pvrdma_get_netdev(struct ib_device *ibdev, | |
| 147 | + u8 port_num) | |
| 148 | +{ | |
| 149 | + struct net_device *netdev; | |
| 150 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 151 | + | |
| 152 | + if (port_num != 1) | |
| 153 | + return NULL; | |
| 154 | + | |
| 155 | + rcu_read_lock(); | |
| 156 | + netdev = dev->netdev; | |
| 157 | + if (netdev) | |
| 158 | + dev_hold(netdev); | |
| 159 | + rcu_read_unlock(); | |
| 160 | + | |
| 161 | + return netdev; | |
| 162 | +} | |
| 163 | + | |
| 164 | +static int pvrdma_register_device(struct pvrdma_dev *dev) | |
| 165 | +{ | |
| 166 | + int ret = -1; | |
| 167 | + int i = 0; | |
| 168 | + | |
| 169 | + strlcpy(dev->ib_dev.name, "vmw_pvrdma%d", IB_DEVICE_NAME_MAX); | |
| 170 | + dev->ib_dev.node_guid = dev->dsr->caps.node_guid; | |
| 171 | + dev->sys_image_guid = dev->dsr->caps.sys_image_guid; | |
| 172 | + dev->flags = 0; | |
| 173 | + dev->ib_dev.owner = THIS_MODULE; | |
| 174 | + dev->ib_dev.num_comp_vectors = 1; | |
| 175 | + dev->ib_dev.dma_device = &dev->pdev->dev; | |
| 176 | + dev->ib_dev.uverbs_abi_ver = PVRDMA_UVERBS_ABI_VERSION; | |
| 177 | + dev->ib_dev.uverbs_cmd_mask = | |
| 178 | + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | |
| 179 | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | | |
| 180 | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | | |
| 181 | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | | |
| 182 | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | | |
| 183 | + (1ull << IB_USER_VERBS_CMD_REG_MR) | | |
| 184 | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | | |
| 185 | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | | |
| 186 | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | | |
| 187 | + (1ull << IB_USER_VERBS_CMD_POLL_CQ) | | |
| 188 | + (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | | |
| 189 | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | | |
| 190 | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | | |
| 191 | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | | |
| 192 | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | | |
| 193 | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | |
| 194 | + (1ull << IB_USER_VERBS_CMD_POST_SEND) | | |
| 195 | + (1ull << IB_USER_VERBS_CMD_POST_RECV) | | |
| 196 | + (1ull << IB_USER_VERBS_CMD_CREATE_AH) | | |
| 197 | + (1ull << IB_USER_VERBS_CMD_DESTROY_AH); | |
| 198 | + | |
| 199 | + dev->ib_dev.node_type = RDMA_NODE_IB_CA; | |
| 200 | + dev->ib_dev.phys_port_cnt = dev->dsr->caps.phys_port_cnt; | |
| 201 | + | |
| 202 | + dev->ib_dev.query_device = pvrdma_query_device; | |
| 203 | + dev->ib_dev.query_port = pvrdma_query_port; | |
| 204 | + dev->ib_dev.query_gid = pvrdma_query_gid; | |
| 205 | + dev->ib_dev.query_pkey = pvrdma_query_pkey; | |
| 206 | + dev->ib_dev.modify_port = pvrdma_modify_port; | |
| 207 | + dev->ib_dev.alloc_ucontext = pvrdma_alloc_ucontext; | |
| 208 | + dev->ib_dev.dealloc_ucontext = pvrdma_dealloc_ucontext; | |
| 209 | + dev->ib_dev.mmap = pvrdma_mmap; | |
| 210 | + dev->ib_dev.alloc_pd = pvrdma_alloc_pd; | |
| 211 | + dev->ib_dev.dealloc_pd = pvrdma_dealloc_pd; | |
| 212 | + dev->ib_dev.create_ah = pvrdma_create_ah; | |
| 213 | + dev->ib_dev.destroy_ah = pvrdma_destroy_ah; | |
| 214 | + dev->ib_dev.create_qp = pvrdma_create_qp; | |
| 215 | + dev->ib_dev.modify_qp = pvrdma_modify_qp; | |
| 216 | + dev->ib_dev.query_qp = pvrdma_query_qp; | |
| 217 | + dev->ib_dev.destroy_qp = pvrdma_destroy_qp; | |
| 218 | + dev->ib_dev.post_send = pvrdma_post_send; | |
| 219 | + dev->ib_dev.post_recv = pvrdma_post_recv; | |
| 220 | + dev->ib_dev.create_cq = pvrdma_create_cq; | |
| 221 | + dev->ib_dev.modify_cq = pvrdma_modify_cq; | |
| 222 | + dev->ib_dev.resize_cq = pvrdma_resize_cq; | |
| 223 | + dev->ib_dev.destroy_cq = pvrdma_destroy_cq; | |
| 224 | + dev->ib_dev.poll_cq = pvrdma_poll_cq; | |
| 225 | + dev->ib_dev.req_notify_cq = pvrdma_req_notify_cq; | |
| 226 | + dev->ib_dev.get_dma_mr = pvrdma_get_dma_mr; | |
| 227 | + dev->ib_dev.reg_user_mr = pvrdma_reg_user_mr; | |
| 228 | + dev->ib_dev.dereg_mr = pvrdma_dereg_mr; | |
| 229 | + dev->ib_dev.alloc_mr = pvrdma_alloc_mr; | |
| 230 | + dev->ib_dev.map_mr_sg = pvrdma_map_mr_sg; | |
| 231 | + dev->ib_dev.add_gid = pvrdma_add_gid; | |
| 232 | + dev->ib_dev.del_gid = pvrdma_del_gid; | |
| 233 | + dev->ib_dev.get_netdev = pvrdma_get_netdev; | |
| 234 | + dev->ib_dev.get_port_immutable = pvrdma_port_immutable; | |
| 235 | + dev->ib_dev.get_link_layer = pvrdma_port_link_layer; | |
| 236 | + dev->ib_dev.get_dev_fw_str = pvrdma_get_fw_ver_str; | |
| 237 | + | |
| 238 | + mutex_init(&dev->port_mutex); | |
| 239 | + spin_lock_init(&dev->desc_lock); | |
| 240 | + | |
| 241 | + dev->cq_tbl = kcalloc(dev->dsr->caps.max_cq, sizeof(void *), | |
| 242 | + GFP_KERNEL); | |
| 243 | + if (!dev->cq_tbl) | |
| 244 | + return ret; | |
| 245 | + spin_lock_init(&dev->cq_tbl_lock); | |
| 246 | + | |
| 247 | + dev->qp_tbl = kcalloc(dev->dsr->caps.max_qp, sizeof(void *), | |
| 248 | + GFP_KERNEL); | |
| 249 | + if (!dev->qp_tbl) | |
| 250 | + goto err_cq_free; | |
| 251 | + spin_lock_init(&dev->qp_tbl_lock); | |
| 252 | + | |
| 253 | + ret = ib_register_device(&dev->ib_dev, NULL); | |
| 254 | + if (ret) | |
| 255 | + goto err_qp_free; | |
| 256 | + | |
| 257 | + for (i = 0; i < ARRAY_SIZE(pvrdma_class_attributes); ++i) { | |
| 258 | + ret = device_create_file(&dev->ib_dev.dev, | |
| 259 | + pvrdma_class_attributes[i]); | |
| 260 | + if (ret) | |
| 261 | + goto err_class; | |
| 262 | + } | |
| 263 | + | |
| 264 | + dev->ib_active = true; | |
| 265 | + | |
| 266 | + return 0; | |
| 267 | + | |
| 268 | +err_class: | |
| 269 | + ib_unregister_device(&dev->ib_dev); | |
| 270 | +err_qp_free: | |
| 271 | + kfree(dev->qp_tbl); | |
| 272 | +err_cq_free: | |
| 273 | + kfree(dev->cq_tbl); | |
| 274 | + | |
| 275 | + return ret; | |
| 276 | +} | |
| 277 | + | |
| 278 | +static irqreturn_t pvrdma_intr0_handler(int irq, void *dev_id) | |
| 279 | +{ | |
| 280 | + u32 icr = PVRDMA_INTR_CAUSE_RESPONSE; | |
| 281 | + struct pvrdma_dev *dev = dev_id; | |
| 282 | + | |
| 283 | + dev_dbg(&dev->pdev->dev, "interrupt 0 (response) handler\n"); | |
| 284 | + | |
| 285 | + if (dev->intr.type != PVRDMA_INTR_TYPE_MSIX) { | |
| 286 | + /* Legacy intr */ | |
| 287 | + icr = pvrdma_read_reg(dev, PVRDMA_REG_ICR); | |
| 288 | + if (icr == 0) | |
| 289 | + return IRQ_NONE; | |
| 290 | + } | |
| 291 | + | |
| 292 | + if (icr == PVRDMA_INTR_CAUSE_RESPONSE) | |
| 293 | + complete(&dev->cmd_done); | |
| 294 | + | |
| 295 | + return IRQ_HANDLED; | |
| 296 | +} | |
| 297 | + | |
| 298 | +static void pvrdma_qp_event(struct pvrdma_dev *dev, u32 qpn, int type) | |
| 299 | +{ | |
| 300 | + struct pvrdma_qp *qp; | |
| 301 | + unsigned long flags; | |
| 302 | + | |
| 303 | + spin_lock_irqsave(&dev->qp_tbl_lock, flags); | |
| 304 | + qp = dev->qp_tbl[qpn % dev->dsr->caps.max_qp]; | |
| 305 | + if (qp) | |
| 306 | + atomic_inc(&qp->refcnt); | |
| 307 | + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); | |
| 308 | + | |
| 309 | + if (qp && qp->ibqp.event_handler) { | |
| 310 | + struct ib_qp *ibqp = &qp->ibqp; | |
| 311 | + struct ib_event e; | |
| 312 | + | |
| 313 | + e.device = ibqp->device; | |
| 314 | + e.element.qp = ibqp; | |
| 315 | + e.event = type; /* 1:1 mapping for now. */ | |
| 316 | + ibqp->event_handler(&e, ibqp->qp_context); | |
| 317 | + } | |
| 318 | + if (qp) { | |
| 319 | + atomic_dec(&qp->refcnt); | |
| 320 | + if (atomic_read(&qp->refcnt) == 0) | |
| 321 | + wake_up(&qp->wait); | |
| 322 | + } | |
| 323 | +} | |
| 324 | + | |
| 325 | +static void pvrdma_cq_event(struct pvrdma_dev *dev, u32 cqn, int type) | |
| 326 | +{ | |
| 327 | + struct pvrdma_cq *cq; | |
| 328 | + unsigned long flags; | |
| 329 | + | |
| 330 | + spin_lock_irqsave(&dev->cq_tbl_lock, flags); | |
| 331 | + cq = dev->cq_tbl[cqn % dev->dsr->caps.max_cq]; | |
| 332 | + if (cq) | |
| 333 | + atomic_inc(&cq->refcnt); | |
| 334 | + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); | |
| 335 | + | |
| 336 | + if (cq && cq->ibcq.event_handler) { | |
| 337 | + struct ib_cq *ibcq = &cq->ibcq; | |
| 338 | + struct ib_event e; | |
| 339 | + | |
| 340 | + e.device = ibcq->device; | |
| 341 | + e.element.cq = ibcq; | |
| 342 | + e.event = type; /* 1:1 mapping for now. */ | |
| 343 | + ibcq->event_handler(&e, ibcq->cq_context); | |
| 344 | + } | |
| 345 | + if (cq) { | |
| 346 | + atomic_dec(&cq->refcnt); | |
| 347 | + if (atomic_read(&cq->refcnt) == 0) | |
| 348 | + wake_up(&cq->wait); | |
| 349 | + } | |
| 350 | +} | |
| 351 | + | |
| 352 | +static void pvrdma_dispatch_event(struct pvrdma_dev *dev, int port, | |
| 353 | + enum ib_event_type event) | |
| 354 | +{ | |
| 355 | + struct ib_event ib_event; | |
| 356 | + | |
| 357 | + memset(&ib_event, 0, sizeof(ib_event)); | |
| 358 | + ib_event.device = &dev->ib_dev; | |
| 359 | + ib_event.element.port_num = port; | |
| 360 | + ib_event.event = event; | |
| 361 | + ib_dispatch_event(&ib_event); | |
| 362 | +} | |
| 363 | + | |
| 364 | +static void pvrdma_dev_event(struct pvrdma_dev *dev, u8 port, int type) | |
| 365 | +{ | |
| 366 | + if (port < 1 || port > dev->dsr->caps.phys_port_cnt) { | |
| 367 | + dev_warn(&dev->pdev->dev, "event on port %d\n", port); | |
| 368 | + return; | |
| 369 | + } | |
| 370 | + | |
| 371 | + pvrdma_dispatch_event(dev, port, type); | |
| 372 | +} | |
| 373 | + | |
| 374 | +static inline struct pvrdma_eqe *get_eqe(struct pvrdma_dev *dev, unsigned int i) | |
| 375 | +{ | |
| 376 | + return (struct pvrdma_eqe *)pvrdma_page_dir_get_ptr( | |
| 377 | + &dev->async_pdir, | |
| 378 | + PAGE_SIZE + | |
| 379 | + sizeof(struct pvrdma_eqe) * i); | |
| 380 | +} | |
| 381 | + | |
| 382 | +static irqreturn_t pvrdma_intr1_handler(int irq, void *dev_id) | |
| 383 | +{ | |
| 384 | + struct pvrdma_dev *dev = dev_id; | |
| 385 | + struct pvrdma_ring *ring = &dev->async_ring_state->rx; | |
| 386 | + int ring_slots = (dev->dsr->async_ring_pages.num_pages - 1) * | |
| 387 | + PAGE_SIZE / sizeof(struct pvrdma_eqe); | |
| 388 | + unsigned int head; | |
| 389 | + | |
| 390 | + dev_dbg(&dev->pdev->dev, "interrupt 1 (async event) handler\n"); | |
| 391 | + | |
| 392 | + /* | |
| 393 | + * Don't process events until the IB device is registered. Otherwise | |
| 394 | + * we'll try to ib_dispatch_event() on an invalid device. | |
| 395 | + */ | |
| 396 | + if (!dev->ib_active) | |
| 397 | + return IRQ_HANDLED; | |
| 398 | + | |
| 399 | + while (pvrdma_idx_ring_has_data(ring, ring_slots, &head) > 0) { | |
| 400 | + struct pvrdma_eqe *eqe; | |
| 401 | + | |
| 402 | + eqe = get_eqe(dev, head); | |
| 403 | + | |
| 404 | + switch (eqe->type) { | |
| 405 | + case PVRDMA_EVENT_QP_FATAL: | |
| 406 | + case PVRDMA_EVENT_QP_REQ_ERR: | |
| 407 | + case PVRDMA_EVENT_QP_ACCESS_ERR: | |
| 408 | + case PVRDMA_EVENT_COMM_EST: | |
| 409 | + case PVRDMA_EVENT_SQ_DRAINED: | |
| 410 | + case PVRDMA_EVENT_PATH_MIG: | |
| 411 | + case PVRDMA_EVENT_PATH_MIG_ERR: | |
| 412 | + case PVRDMA_EVENT_QP_LAST_WQE_REACHED: | |
| 413 | + pvrdma_qp_event(dev, eqe->info, eqe->type); | |
| 414 | + break; | |
| 415 | + | |
| 416 | + case PVRDMA_EVENT_CQ_ERR: | |
| 417 | + pvrdma_cq_event(dev, eqe->info, eqe->type); | |
| 418 | + break; | |
| 419 | + | |
| 420 | + case PVRDMA_EVENT_SRQ_ERR: | |
| 421 | + case PVRDMA_EVENT_SRQ_LIMIT_REACHED: | |
| 422 | + break; | |
| 423 | + | |
| 424 | + case PVRDMA_EVENT_PORT_ACTIVE: | |
| 425 | + case PVRDMA_EVENT_PORT_ERR: | |
| 426 | + case PVRDMA_EVENT_LID_CHANGE: | |
| 427 | + case PVRDMA_EVENT_PKEY_CHANGE: | |
| 428 | + case PVRDMA_EVENT_SM_CHANGE: | |
| 429 | + case PVRDMA_EVENT_CLIENT_REREGISTER: | |
| 430 | + case PVRDMA_EVENT_GID_CHANGE: | |
| 431 | + pvrdma_dev_event(dev, eqe->info, eqe->type); | |
| 432 | + break; | |
| 433 | + | |
| 434 | + case PVRDMA_EVENT_DEVICE_FATAL: | |
| 435 | + pvrdma_dev_event(dev, 1, eqe->type); | |
| 436 | + break; | |
| 437 | + | |
| 438 | + default: | |
| 439 | + break; | |
| 440 | + } | |
| 441 | + | |
| 442 | + pvrdma_idx_ring_inc(&ring->cons_head, ring_slots); | |
| 443 | + } | |
| 444 | + | |
| 445 | + return IRQ_HANDLED; | |
| 446 | +} | |
| 447 | + | |
| 448 | +static inline struct pvrdma_cqne *get_cqne(struct pvrdma_dev *dev, | |
| 449 | + unsigned int i) | |
| 450 | +{ | |
| 451 | + return (struct pvrdma_cqne *)pvrdma_page_dir_get_ptr( | |
| 452 | + &dev->cq_pdir, | |
| 453 | + PAGE_SIZE + | |
| 454 | + sizeof(struct pvrdma_cqne) * i); | |
| 455 | +} | |
| 456 | + | |
| 457 | +static irqreturn_t pvrdma_intrx_handler(int irq, void *dev_id) | |
| 458 | +{ | |
| 459 | + struct pvrdma_dev *dev = dev_id; | |
| 460 | + struct pvrdma_ring *ring = &dev->cq_ring_state->rx; | |
| 461 | + int ring_slots = (dev->dsr->cq_ring_pages.num_pages - 1) * PAGE_SIZE / | |
| 462 | + sizeof(struct pvrdma_cqne); | |
| 463 | + unsigned int head; | |
| 464 | + unsigned long flags; | |
| 465 | + | |
| 466 | + dev_dbg(&dev->pdev->dev, "interrupt x (completion) handler\n"); | |
| 467 | + | |
| 468 | + while (pvrdma_idx_ring_has_data(ring, ring_slots, &head) > 0) { | |
| 469 | + struct pvrdma_cqne *cqne; | |
| 470 | + struct pvrdma_cq *cq; | |
| 471 | + | |
| 472 | + cqne = get_cqne(dev, head); | |
| 473 | + spin_lock_irqsave(&dev->cq_tbl_lock, flags); | |
| 474 | + cq = dev->cq_tbl[cqne->info % dev->dsr->caps.max_cq]; | |
| 475 | + if (cq) | |
| 476 | + atomic_inc(&cq->refcnt); | |
| 477 | + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); | |
| 478 | + | |
| 479 | + if (cq && cq->ibcq.comp_handler) | |
| 480 | + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); | |
| 481 | + if (cq) { | |
| 482 | + atomic_dec(&cq->refcnt); | |
| 483 | + if (atomic_read(&cq->refcnt)) | |
| 484 | + wake_up(&cq->wait); | |
| 485 | + } | |
| 486 | + pvrdma_idx_ring_inc(&ring->cons_head, ring_slots); | |
| 487 | + } | |
| 488 | + | |
| 489 | + return IRQ_HANDLED; | |
| 490 | +} | |
| 491 | + | |
| 492 | +static void pvrdma_disable_msi_all(struct pvrdma_dev *dev) | |
| 493 | +{ | |
| 494 | + if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX) | |
| 495 | + pci_disable_msix(dev->pdev); | |
| 496 | + else if (dev->intr.type == PVRDMA_INTR_TYPE_MSI) | |
| 497 | + pci_disable_msi(dev->pdev); | |
| 498 | +} | |
| 499 | + | |
| 500 | +static void pvrdma_free_irq(struct pvrdma_dev *dev) | |
| 501 | +{ | |
| 502 | + int i; | |
| 503 | + | |
| 504 | + dev_dbg(&dev->pdev->dev, "freeing interrupts\n"); | |
| 505 | + | |
| 506 | + if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX) { | |
| 507 | + for (i = 0; i < dev->intr.size; i++) { | |
| 508 | + if (dev->intr.enabled[i]) { | |
| 509 | + free_irq(dev->intr.msix_entry[i].vector, dev); | |
| 510 | + dev->intr.enabled[i] = 0; | |
| 511 | + } | |
| 512 | + } | |
| 513 | + } else if (dev->intr.type == PVRDMA_INTR_TYPE_INTX || | |
| 514 | + dev->intr.type == PVRDMA_INTR_TYPE_MSI) { | |
| 515 | + free_irq(dev->pdev->irq, dev); | |
| 516 | + } | |
| 517 | +} | |
| 518 | + | |
| 519 | +static void pvrdma_enable_intrs(struct pvrdma_dev *dev) | |
| 520 | +{ | |
| 521 | + dev_dbg(&dev->pdev->dev, "enable interrupts\n"); | |
| 522 | + pvrdma_write_reg(dev, PVRDMA_REG_IMR, 0); | |
| 523 | +} | |
| 524 | + | |
| 525 | +static void pvrdma_disable_intrs(struct pvrdma_dev *dev) | |
| 526 | +{ | |
| 527 | + dev_dbg(&dev->pdev->dev, "disable interrupts\n"); | |
| 528 | + pvrdma_write_reg(dev, PVRDMA_REG_IMR, ~0); | |
| 529 | +} | |
| 530 | + | |
| 531 | +static int pvrdma_enable_msix(struct pci_dev *pdev, struct pvrdma_dev *dev) | |
| 532 | +{ | |
| 533 | + int i; | |
| 534 | + int ret; | |
| 535 | + | |
| 536 | + for (i = 0; i < PVRDMA_MAX_INTERRUPTS; i++) { | |
| 537 | + dev->intr.msix_entry[i].entry = i; | |
| 538 | + dev->intr.msix_entry[i].vector = i; | |
| 539 | + | |
| 540 | + switch (i) { | |
| 541 | + case 0: | |
| 542 | + /* CMD ring handler */ | |
| 543 | + dev->intr.handler[i] = pvrdma_intr0_handler; | |
| 544 | + break; | |
| 545 | + case 1: | |
| 546 | + /* Async event ring handler */ | |
| 547 | + dev->intr.handler[i] = pvrdma_intr1_handler; | |
| 548 | + break; | |
| 549 | + default: | |
| 550 | + /* Completion queue handler */ | |
| 551 | + dev->intr.handler[i] = pvrdma_intrx_handler; | |
| 552 | + break; | |
| 553 | + } | |
| 554 | + } | |
| 555 | + | |
| 556 | + ret = pci_enable_msix(pdev, dev->intr.msix_entry, | |
| 557 | + PVRDMA_MAX_INTERRUPTS); | |
| 558 | + if (!ret) { | |
| 559 | + dev->intr.type = PVRDMA_INTR_TYPE_MSIX; | |
| 560 | + dev->intr.size = PVRDMA_MAX_INTERRUPTS; | |
| 561 | + } else if (ret > 0) { | |
| 562 | + ret = pci_enable_msix(pdev, dev->intr.msix_entry, ret); | |
| 563 | + if (!ret) { | |
| 564 | + dev->intr.type = PVRDMA_INTR_TYPE_MSIX; | |
| 565 | + dev->intr.size = ret; | |
| 566 | + } else { | |
| 567 | + dev->intr.size = 0; | |
| 568 | + } | |
| 569 | + } | |
| 570 | + | |
| 571 | + dev_dbg(&pdev->dev, "using interrupt type %d, size %d\n", | |
| 572 | + dev->intr.type, dev->intr.size); | |
| 573 | + | |
| 574 | + return ret; | |
| 575 | +} | |
| 576 | + | |
| 577 | +static int pvrdma_alloc_intrs(struct pvrdma_dev *dev) | |
| 578 | +{ | |
| 579 | + int ret = 0; | |
| 580 | + int i; | |
| 581 | + | |
| 582 | + if (pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX) && | |
| 583 | + pvrdma_enable_msix(dev->pdev, dev)) { | |
| 584 | + /* Try MSI */ | |
| 585 | + ret = pci_enable_msi(dev->pdev); | |
| 586 | + if (!ret) { | |
| 587 | + dev->intr.type = PVRDMA_INTR_TYPE_MSI; | |
| 588 | + } else { | |
| 589 | + /* Legacy INTR */ | |
| 590 | + dev->intr.type = PVRDMA_INTR_TYPE_INTX; | |
| 591 | + } | |
| 592 | + } | |
| 593 | + | |
| 594 | + /* Request First IRQ */ | |
| 595 | + switch (dev->intr.type) { | |
| 596 | + case PVRDMA_INTR_TYPE_INTX: | |
| 597 | + case PVRDMA_INTR_TYPE_MSI: | |
| 598 | + ret = request_irq(dev->pdev->irq, pvrdma_intr0_handler, | |
| 599 | + IRQF_SHARED, DRV_NAME, dev); | |
| 600 | + if (ret) { | |
| 601 | + dev_err(&dev->pdev->dev, | |
| 602 | + "failed to request interrupt\n"); | |
| 603 | + goto disable_msi; | |
| 604 | + } | |
| 605 | + break; | |
| 606 | + case PVRDMA_INTR_TYPE_MSIX: | |
| 607 | + ret = request_irq(dev->intr.msix_entry[0].vector, | |
| 608 | + pvrdma_intr0_handler, 0, DRV_NAME, dev); | |
| 609 | + if (ret) { | |
| 610 | + dev_err(&dev->pdev->dev, | |
| 611 | + "failed to request interrupt 0\n"); | |
| 612 | + goto disable_msi; | |
| 613 | + } | |
| 614 | + dev->intr.enabled[0] = 1; | |
| 615 | + break; | |
| 616 | + default: | |
| 617 | + /* Not reached */ | |
| 618 | + break; | |
| 619 | + } | |
| 620 | + | |
| 621 | + /* For MSIX: request intr for each vector */ | |
| 622 | + if (dev->intr.size > 1) { | |
| 623 | + ret = request_irq(dev->intr.msix_entry[1].vector, | |
| 624 | + pvrdma_intr1_handler, 0, DRV_NAME, dev); | |
| 625 | + if (ret) { | |
| 626 | + dev_err(&dev->pdev->dev, | |
| 627 | + "failed to request interrupt 1\n"); | |
| 628 | + goto free_irq; | |
| 629 | + } | |
| 630 | + dev->intr.enabled[1] = 1; | |
| 631 | + | |
| 632 | + for (i = 2; i < dev->intr.size; i++) { | |
| 633 | + ret = request_irq(dev->intr.msix_entry[i].vector, | |
| 634 | + pvrdma_intrx_handler, 0, | |
| 635 | + DRV_NAME, dev); | |
| 636 | + if (ret) { | |
| 637 | + dev_err(&dev->pdev->dev, | |
| 638 | + "failed to request interrupt %d\n", i); | |
| 639 | + goto free_irq; | |
| 640 | + } | |
| 641 | + dev->intr.enabled[i] = 1; | |
| 642 | + } | |
| 643 | + } | |
| 644 | + | |
| 645 | + return 0; | |
| 646 | + | |
| 647 | +free_irq: | |
| 648 | + pvrdma_free_irq(dev); | |
| 649 | +disable_msi: | |
| 650 | + pvrdma_disable_msi_all(dev); | |
| 651 | + return ret; | |
| 652 | +} | |
| 653 | + | |
| 654 | +static void pvrdma_free_slots(struct pvrdma_dev *dev) | |
| 655 | +{ | |
| 656 | + struct pci_dev *pdev = dev->pdev; | |
| 657 | + | |
| 658 | + if (dev->resp_slot) | |
| 659 | + dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->resp_slot, | |
| 660 | + dev->dsr->resp_slot_dma); | |
| 661 | + if (dev->cmd_slot) | |
| 662 | + dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->cmd_slot, | |
| 663 | + dev->dsr->cmd_slot_dma); | |
| 664 | +} | |
| 665 | + | |
| 666 | +static int pvrdma_add_gid_at_index(struct pvrdma_dev *dev, | |
| 667 | + const union ib_gid *gid, | |
| 668 | + int index) | |
| 669 | +{ | |
| 670 | + int ret; | |
| 671 | + union pvrdma_cmd_req req; | |
| 672 | + struct pvrdma_cmd_create_bind *cmd_bind = &req.create_bind; | |
| 673 | + | |
| 674 | + if (!dev->sgid_tbl) { | |
| 675 | + dev_warn(&dev->pdev->dev, "sgid table not initialized\n"); | |
| 676 | + return -EINVAL; | |
| 677 | + } | |
| 678 | + | |
| 679 | + memset(cmd_bind, 0, sizeof(*cmd_bind)); | |
| 680 | + cmd_bind->hdr.cmd = PVRDMA_CMD_CREATE_BIND; | |
| 681 | + memcpy(cmd_bind->new_gid, gid->raw, 16); | |
| 682 | + cmd_bind->mtu = ib_mtu_enum_to_int(IB_MTU_1024); | |
| 683 | + cmd_bind->vlan = 0xfff; | |
| 684 | + cmd_bind->index = index; | |
| 685 | + cmd_bind->gid_type = PVRDMA_GID_TYPE_FLAG_ROCE_V1; | |
| 686 | + | |
| 687 | + ret = pvrdma_cmd_post(dev, &req, NULL, 0); | |
| 688 | + if (ret < 0) { | |
| 689 | + dev_warn(&dev->pdev->dev, | |
| 690 | + "could not create binding, error: %d\n", ret); | |
| 691 | + return -EFAULT; | |
| 692 | + } | |
| 693 | + memcpy(&dev->sgid_tbl[index], gid, sizeof(*gid)); | |
| 694 | + return 0; | |
| 695 | +} | |
| 696 | + | |
| 697 | +static int pvrdma_add_gid(struct ib_device *ibdev, | |
| 698 | + u8 port_num, | |
| 699 | + unsigned int index, | |
| 700 | + const union ib_gid *gid, | |
| 701 | + const struct ib_gid_attr *attr, | |
| 702 | + void **context) | |
| 703 | +{ | |
| 704 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 705 | + | |
| 706 | + return pvrdma_add_gid_at_index(dev, gid, index); | |
| 707 | +} | |
| 708 | + | |
| 709 | +static int pvrdma_del_gid_at_index(struct pvrdma_dev *dev, int index) | |
| 710 | +{ | |
| 711 | + int ret; | |
| 712 | + union pvrdma_cmd_req req; | |
| 713 | + struct pvrdma_cmd_destroy_bind *cmd_dest = &req.destroy_bind; | |
| 714 | + | |
| 715 | + /* Update sgid table. */ | |
| 716 | + if (!dev->sgid_tbl) { | |
| 717 | + dev_warn(&dev->pdev->dev, "sgid table not initialized\n"); | |
| 718 | + return -EINVAL; | |
| 719 | + } | |
| 720 | + | |
| 721 | + memset(cmd_dest, 0, sizeof(*cmd_dest)); | |
| 722 | + cmd_dest->hdr.cmd = PVRDMA_CMD_DESTROY_BIND; | |
| 723 | + memcpy(cmd_dest->dest_gid, &dev->sgid_tbl[index], 16); | |
| 724 | + cmd_dest->index = index; | |
| 725 | + | |
| 726 | + ret = pvrdma_cmd_post(dev, &req, NULL, 0); | |
| 727 | + if (ret < 0) { | |
| 728 | + dev_warn(&dev->pdev->dev, | |
| 729 | + "could not destroy binding, error: %d\n", ret); | |
| 730 | + return ret; | |
| 731 | + } | |
| 732 | + memset(&dev->sgid_tbl[index], 0, 16); | |
| 733 | + return 0; | |
| 734 | +} | |
| 735 | + | |
| 736 | +static int pvrdma_del_gid(struct ib_device *ibdev, | |
| 737 | + u8 port_num, | |
| 738 | + unsigned int index, | |
| 739 | + void **context) | |
| 740 | +{ | |
| 741 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 742 | + | |
| 743 | + dev_dbg(&dev->pdev->dev, "removing gid at index %u from %s", | |
| 744 | + index, dev->netdev->name); | |
| 745 | + | |
| 746 | + return pvrdma_del_gid_at_index(dev, index); | |
| 747 | +} | |
| 748 | + | |
| 749 | +static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev, | |
| 750 | + unsigned long event) | |
| 751 | +{ | |
| 752 | + switch (event) { | |
| 753 | + case NETDEV_REBOOT: | |
| 754 | + case NETDEV_DOWN: | |
| 755 | + pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ERR); | |
| 756 | + break; | |
| 757 | + case NETDEV_UP: | |
| 758 | + pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE); | |
| 759 | + break; | |
| 760 | + default: | |
| 761 | + dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n", | |
| 762 | + event, dev->ib_dev.name); | |
| 763 | + break; | |
| 764 | + } | |
| 765 | +} | |
| 766 | + | |
| 767 | +static void pvrdma_netdevice_event_work(struct work_struct *work) | |
| 768 | +{ | |
| 769 | + struct pvrdma_netdevice_work *netdev_work; | |
| 770 | + struct pvrdma_dev *dev; | |
| 771 | + | |
| 772 | + netdev_work = container_of(work, struct pvrdma_netdevice_work, work); | |
| 773 | + | |
| 774 | + mutex_lock(&pvrdma_device_list_lock); | |
| 775 | + list_for_each_entry(dev, &pvrdma_device_list, device_link) { | |
| 776 | + if (dev->netdev == netdev_work->event_netdev) { | |
| 777 | + pvrdma_netdevice_event_handle(dev, netdev_work->event); | |
| 778 | + break; | |
| 779 | + } | |
| 780 | + } | |
| 781 | + mutex_unlock(&pvrdma_device_list_lock); | |
| 782 | + | |
| 783 | + kfree(netdev_work); | |
| 784 | +} | |
| 785 | + | |
| 786 | +static int pvrdma_netdevice_event(struct notifier_block *this, | |
| 787 | + unsigned long event, void *ptr) | |
| 788 | +{ | |
| 789 | + struct net_device *event_netdev = netdev_notifier_info_to_dev(ptr); | |
| 790 | + struct pvrdma_netdevice_work *netdev_work; | |
| 791 | + | |
| 792 | + netdev_work = kmalloc(sizeof(*netdev_work), GFP_ATOMIC); | |
| 793 | + if (!netdev_work) | |
| 794 | + return NOTIFY_BAD; | |
| 795 | + | |
| 796 | + INIT_WORK(&netdev_work->work, pvrdma_netdevice_event_work); | |
| 797 | + netdev_work->event_netdev = event_netdev; | |
| 798 | + netdev_work->event = event; | |
| 799 | + queue_work(event_wq, &netdev_work->work); | |
| 800 | + | |
| 801 | + return NOTIFY_DONE; | |
| 802 | +} | |
| 803 | + | |
| 804 | +static int pvrdma_pci_probe(struct pci_dev *pdev, | |
| 805 | + const struct pci_device_id *id) | |
| 806 | +{ | |
| 807 | + struct pci_dev *pdev_net; | |
| 808 | + struct pvrdma_dev *dev; | |
| 809 | + int ret; | |
| 810 | + unsigned long start; | |
| 811 | + unsigned long len; | |
| 812 | + unsigned int version; | |
| 813 | + dma_addr_t slot_dma = 0; | |
| 814 | + | |
| 815 | + dev_dbg(&pdev->dev, "initializing driver %s\n", pci_name(pdev)); | |
| 816 | + | |
| 817 | + /* Allocate zero-out device */ | |
| 818 | + dev = (struct pvrdma_dev *)ib_alloc_device(sizeof(*dev)); | |
| 819 | + if (!dev) { | |
| 820 | + dev_err(&pdev->dev, "failed to allocate IB device\n"); | |
| 821 | + return -ENOMEM; | |
| 822 | + } | |
| 823 | + | |
| 824 | + mutex_lock(&pvrdma_device_list_lock); | |
| 825 | + list_add(&dev->device_link, &pvrdma_device_list); | |
| 826 | + mutex_unlock(&pvrdma_device_list_lock); | |
| 827 | + | |
| 828 | + ret = pvrdma_init_device(dev); | |
| 829 | + if (ret) | |
| 830 | + goto err_free_device; | |
| 831 | + | |
| 832 | + dev->pdev = pdev; | |
| 833 | + pci_set_drvdata(pdev, dev); | |
| 834 | + | |
| 835 | + ret = pci_enable_device(pdev); | |
| 836 | + if (ret) { | |
| 837 | + dev_err(&pdev->dev, "cannot enable PCI device\n"); | |
| 838 | + goto err_free_device; | |
| 839 | + } | |
| 840 | + | |
| 841 | + dev_dbg(&pdev->dev, "PCI resource flags BAR0 %#lx\n", | |
| 842 | + pci_resource_flags(pdev, 0)); | |
| 843 | + dev_dbg(&pdev->dev, "PCI resource len %#llx\n", | |
| 844 | + (unsigned long long)pci_resource_len(pdev, 0)); | |
| 845 | + dev_dbg(&pdev->dev, "PCI resource start %#llx\n", | |
| 846 | + (unsigned long long)pci_resource_start(pdev, 0)); | |
| 847 | + dev_dbg(&pdev->dev, "PCI resource flags BAR1 %#lx\n", | |
| 848 | + pci_resource_flags(pdev, 1)); | |
| 849 | + dev_dbg(&pdev->dev, "PCI resource len %#llx\n", | |
| 850 | + (unsigned long long)pci_resource_len(pdev, 1)); | |
| 851 | + dev_dbg(&pdev->dev, "PCI resource start %#llx\n", | |
| 852 | + (unsigned long long)pci_resource_start(pdev, 1)); | |
| 853 | + | |
| 854 | + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || | |
| 855 | + !(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { | |
| 856 | + dev_err(&pdev->dev, "PCI BAR region not MMIO\n"); | |
| 857 | + ret = -ENOMEM; | |
| 858 | + goto err_free_device; | |
| 859 | + } | |
| 860 | + | |
| 861 | + ret = pci_request_regions(pdev, DRV_NAME); | |
| 862 | + if (ret) { | |
| 863 | + dev_err(&pdev->dev, "cannot request PCI resources\n"); | |
| 864 | + goto err_disable_pdev; | |
| 865 | + } | |
| 866 | + | |
| 867 | + /* Enable 64-Bit DMA */ | |
| 868 | + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { | |
| 869 | + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); | |
| 870 | + if (ret != 0) { | |
| 871 | + dev_err(&pdev->dev, | |
| 872 | + "pci_set_consistent_dma_mask failed\n"); | |
| 873 | + goto err_free_resource; | |
| 874 | + } | |
| 875 | + } else { | |
| 876 | + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | |
| 877 | + if (ret != 0) { | |
| 878 | + dev_err(&pdev->dev, | |
| 879 | + "pci_set_dma_mask failed\n"); | |
| 880 | + goto err_free_resource; | |
| 881 | + } | |
| 882 | + } | |
| 883 | + | |
| 884 | + pci_set_master(pdev); | |
| 885 | + | |
| 886 | + /* Map register space */ | |
| 887 | + start = pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_REG); | |
| 888 | + len = pci_resource_len(dev->pdev, PVRDMA_PCI_RESOURCE_REG); | |
| 889 | + dev->regs = ioremap(start, len); | |
| 890 | + if (!dev->regs) { | |
| 891 | + dev_err(&pdev->dev, "register mapping failed\n"); | |
| 892 | + ret = -ENOMEM; | |
| 893 | + goto err_free_resource; | |
| 894 | + } | |
| 895 | + | |
| 896 | + /* Setup per-device UAR. */ | |
| 897 | + dev->driver_uar.index = 0; | |
| 898 | + dev->driver_uar.pfn = | |
| 899 | + pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >> | |
| 900 | + PAGE_SHIFT; | |
| 901 | + dev->driver_uar.map = | |
| 902 | + ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); | |
| 903 | + if (!dev->driver_uar.map) { | |
| 904 | + dev_err(&pdev->dev, "failed to remap UAR pages\n"); | |
| 905 | + ret = -ENOMEM; | |
| 906 | + goto err_unmap_regs; | |
| 907 | + } | |
| 908 | + | |
| 909 | + version = pvrdma_read_reg(dev, PVRDMA_REG_VERSION); | |
| 910 | + dev_info(&pdev->dev, "device version %d, driver version %d\n", | |
| 911 | + version, PVRDMA_VERSION); | |
| 912 | + if (version < PVRDMA_VERSION) { | |
| 913 | + dev_err(&pdev->dev, "incompatible device version\n"); | |
| 914 | + goto err_uar_unmap; | |
| 915 | + } | |
| 916 | + | |
| 917 | + dev->dsr = dma_alloc_coherent(&pdev->dev, sizeof(*dev->dsr), | |
| 918 | + &dev->dsrbase, GFP_KERNEL); | |
| 919 | + if (!dev->dsr) { | |
| 920 | + dev_err(&pdev->dev, "failed to allocate shared region\n"); | |
| 921 | + ret = -ENOMEM; | |
| 922 | + goto err_uar_unmap; | |
| 923 | + } | |
| 924 | + | |
| 925 | + /* Setup the shared region */ | |
| 926 | + memset(dev->dsr, 0, sizeof(*dev->dsr)); | |
| 927 | + dev->dsr->driver_version = PVRDMA_VERSION; | |
| 928 | + dev->dsr->gos_info.gos_bits = sizeof(void *) == 4 ? | |
| 929 | + PVRDMA_GOS_BITS_32 : | |
| 930 | + PVRDMA_GOS_BITS_64; | |
| 931 | + dev->dsr->gos_info.gos_type = PVRDMA_GOS_TYPE_LINUX; | |
| 932 | + dev->dsr->gos_info.gos_ver = 1; | |
| 933 | + dev->dsr->uar_pfn = dev->driver_uar.pfn; | |
| 934 | + | |
| 935 | + /* Command slot. */ | |
| 936 | + dev->cmd_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, | |
| 937 | + &slot_dma, GFP_KERNEL); | |
| 938 | + if (!dev->cmd_slot) { | |
| 939 | + ret = -ENOMEM; | |
| 940 | + goto err_free_dsr; | |
| 941 | + } | |
| 942 | + | |
| 943 | + dev->dsr->cmd_slot_dma = (u64)slot_dma; | |
| 944 | + | |
| 945 | + /* Response slot. */ | |
| 946 | + dev->resp_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, | |
| 947 | + &slot_dma, GFP_KERNEL); | |
| 948 | + if (!dev->resp_slot) { | |
| 949 | + ret = -ENOMEM; | |
| 950 | + goto err_free_slots; | |
| 951 | + } | |
| 952 | + | |
| 953 | + dev->dsr->resp_slot_dma = (u64)slot_dma; | |
| 954 | + | |
| 955 | + /* Async event ring */ | |
| 956 | + dev->dsr->async_ring_pages.num_pages = 4; | |
| 957 | + ret = pvrdma_page_dir_init(dev, &dev->async_pdir, | |
| 958 | + dev->dsr->async_ring_pages.num_pages, true); | |
| 959 | + if (ret) | |
| 960 | + goto err_free_slots; | |
| 961 | + dev->async_ring_state = dev->async_pdir.pages[0]; | |
| 962 | + dev->dsr->async_ring_pages.pdir_dma = dev->async_pdir.dir_dma; | |
| 963 | + | |
| 964 | + /* CQ notification ring */ | |
| 965 | + dev->dsr->cq_ring_pages.num_pages = 4; | |
| 966 | + ret = pvrdma_page_dir_init(dev, &dev->cq_pdir, | |
| 967 | + dev->dsr->cq_ring_pages.num_pages, true); | |
| 968 | + if (ret) | |
| 969 | + goto err_free_async_ring; | |
| 970 | + dev->cq_ring_state = dev->cq_pdir.pages[0]; | |
| 971 | + dev->dsr->cq_ring_pages.pdir_dma = dev->cq_pdir.dir_dma; | |
| 972 | + | |
| 973 | + /* | |
| 974 | + * Write the PA of the shared region to the device. The writes must be | |
| 975 | + * ordered such that the high bits are written last. When the writes | |
| 976 | + * complete, the device will have filled out the capabilities. | |
| 977 | + */ | |
| 978 | + | |
| 979 | + pvrdma_write_reg(dev, PVRDMA_REG_DSRLOW, (u32)dev->dsrbase); | |
| 980 | + pvrdma_write_reg(dev, PVRDMA_REG_DSRHIGH, | |
| 981 | + (u32)((u64)(dev->dsrbase) >> 32)); | |
| 982 | + | |
| 983 | + /* Make sure the write is complete before reading status. */ | |
| 984 | + mb(); | |
| 985 | + | |
| 986 | + /* Currently, the driver only supports RoCE mode. */ | |
| 987 | + if (dev->dsr->caps.mode != PVRDMA_DEVICE_MODE_ROCE) { | |
| 988 | + dev_err(&pdev->dev, "unsupported transport %d\n", | |
| 989 | + dev->dsr->caps.mode); | |
| 990 | + ret = -EFAULT; | |
| 991 | + goto err_free_cq_ring; | |
| 992 | + } | |
| 993 | + | |
| 994 | + /* Currently, the driver only supports RoCE V1. */ | |
| 995 | + if (!(dev->dsr->caps.gid_types & PVRDMA_GID_TYPE_FLAG_ROCE_V1)) { | |
| 996 | + dev_err(&pdev->dev, "driver needs RoCE v1 support\n"); | |
| 997 | + ret = -EFAULT; | |
| 998 | + goto err_free_cq_ring; | |
| 999 | + } | |
| 1000 | + | |
| 1001 | + /* Paired vmxnet3 will have same bus, slot. But func will be 0 */ | |
| 1002 | + pdev_net = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); | |
| 1003 | + if (!pdev_net) { | |
| 1004 | + dev_err(&pdev->dev, "failed to find paired net device\n"); | |
| 1005 | + ret = -ENODEV; | |
| 1006 | + goto err_free_cq_ring; | |
| 1007 | + } | |
| 1008 | + | |
| 1009 | + if (pdev_net->vendor != PCI_VENDOR_ID_VMWARE || | |
| 1010 | + pdev_net->device != PCI_DEVICE_ID_VMWARE_VMXNET3) { | |
| 1011 | + dev_err(&pdev->dev, "failed to find paired vmxnet3 device\n"); | |
| 1012 | + pci_dev_put(pdev_net); | |
| 1013 | + ret = -ENODEV; | |
| 1014 | + goto err_free_cq_ring; | |
| 1015 | + } | |
| 1016 | + | |
| 1017 | + dev->netdev = pci_get_drvdata(pdev_net); | |
| 1018 | + pci_dev_put(pdev_net); | |
| 1019 | + if (!dev->netdev) { | |
| 1020 | + dev_err(&pdev->dev, "failed to get vmxnet3 device\n"); | |
| 1021 | + ret = -ENODEV; | |
| 1022 | + goto err_free_cq_ring; | |
| 1023 | + } | |
| 1024 | + | |
| 1025 | + dev_info(&pdev->dev, "paired device to %s\n", dev->netdev->name); | |
| 1026 | + | |
| 1027 | + /* Interrupt setup */ | |
| 1028 | + ret = pvrdma_alloc_intrs(dev); | |
| 1029 | + if (ret) { | |
| 1030 | + dev_err(&pdev->dev, "failed to allocate interrupts\n"); | |
| 1031 | + ret = -ENOMEM; | |
| 1032 | + goto err_netdevice; | |
| 1033 | + } | |
| 1034 | + | |
| 1035 | + /* Allocate UAR table. */ | |
| 1036 | + ret = pvrdma_uar_table_init(dev); | |
| 1037 | + if (ret) { | |
| 1038 | + dev_err(&pdev->dev, "failed to allocate UAR table\n"); | |
| 1039 | + ret = -ENOMEM; | |
| 1040 | + goto err_free_intrs; | |
| 1041 | + } | |
| 1042 | + | |
| 1043 | + /* Allocate GID table */ | |
| 1044 | + dev->sgid_tbl = kcalloc(dev->dsr->caps.gid_tbl_len, | |
| 1045 | + sizeof(union ib_gid), GFP_KERNEL); | |
| 1046 | + if (!dev->sgid_tbl) { | |
| 1047 | + ret = -ENOMEM; | |
| 1048 | + goto err_free_uar_table; | |
| 1049 | + } | |
| 1050 | + dev_dbg(&pdev->dev, "gid table len %d\n", dev->dsr->caps.gid_tbl_len); | |
| 1051 | + | |
| 1052 | + pvrdma_enable_intrs(dev); | |
| 1053 | + | |
| 1054 | + /* Activate pvrdma device */ | |
| 1055 | + pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_ACTIVATE); | |
| 1056 | + | |
| 1057 | + /* Make sure the write is complete before reading status. */ | |
| 1058 | + mb(); | |
| 1059 | + | |
| 1060 | + /* Check if device was successfully activated */ | |
| 1061 | + ret = pvrdma_read_reg(dev, PVRDMA_REG_ERR); | |
| 1062 | + if (ret != 0) { | |
| 1063 | + dev_err(&pdev->dev, "failed to activate device\n"); | |
| 1064 | + ret = -EFAULT; | |
| 1065 | + goto err_disable_intr; | |
| 1066 | + } | |
| 1067 | + | |
| 1068 | + /* Register IB device */ | |
| 1069 | + ret = pvrdma_register_device(dev); | |
| 1070 | + if (ret) { | |
| 1071 | + dev_err(&pdev->dev, "failed to register IB device\n"); | |
| 1072 | + goto err_disable_intr; | |
| 1073 | + } | |
| 1074 | + | |
| 1075 | + dev->nb_netdev.notifier_call = pvrdma_netdevice_event; | |
| 1076 | + ret = register_netdevice_notifier(&dev->nb_netdev); | |
| 1077 | + if (ret) { | |
| 1078 | + dev_err(&pdev->dev, "failed to register netdevice events\n"); | |
| 1079 | + goto err_unreg_ibdev; | |
| 1080 | + } | |
| 1081 | + | |
| 1082 | + dev_info(&pdev->dev, "attached to device\n"); | |
| 1083 | + return 0; | |
| 1084 | + | |
| 1085 | +err_unreg_ibdev: | |
| 1086 | + ib_unregister_device(&dev->ib_dev); | |
| 1087 | +err_disable_intr: | |
| 1088 | + pvrdma_disable_intrs(dev); | |
| 1089 | + kfree(dev->sgid_tbl); | |
| 1090 | +err_free_uar_table: | |
| 1091 | + pvrdma_uar_table_cleanup(dev); | |
| 1092 | +err_free_intrs: | |
| 1093 | + pvrdma_free_irq(dev); | |
| 1094 | + pvrdma_disable_msi_all(dev); | |
| 1095 | +err_netdevice: | |
| 1096 | + unregister_netdevice_notifier(&dev->nb_netdev); | |
| 1097 | +err_free_cq_ring: | |
| 1098 | + pvrdma_page_dir_cleanup(dev, &dev->cq_pdir); | |
| 1099 | +err_free_async_ring: | |
| 1100 | + pvrdma_page_dir_cleanup(dev, &dev->async_pdir); | |
| 1101 | +err_free_slots: | |
| 1102 | + pvrdma_free_slots(dev); | |
| 1103 | +err_free_dsr: | |
| 1104 | + dma_free_coherent(&pdev->dev, sizeof(*dev->dsr), dev->dsr, | |
| 1105 | + dev->dsrbase); | |
| 1106 | +err_uar_unmap: | |
| 1107 | + iounmap(dev->driver_uar.map); | |
| 1108 | +err_unmap_regs: | |
| 1109 | + iounmap(dev->regs); | |
| 1110 | +err_free_resource: | |
| 1111 | + pci_release_regions(pdev); | |
| 1112 | +err_disable_pdev: | |
| 1113 | + pci_disable_device(pdev); | |
| 1114 | + pci_set_drvdata(pdev, NULL); | |
| 1115 | +err_free_device: | |
| 1116 | + mutex_lock(&pvrdma_device_list_lock); | |
| 1117 | + list_del(&dev->device_link); | |
| 1118 | + mutex_unlock(&pvrdma_device_list_lock); | |
| 1119 | + ib_dealloc_device(&dev->ib_dev); | |
| 1120 | + return ret; | |
| 1121 | +} | |
| 1122 | + | |
| 1123 | +static void pvrdma_pci_remove(struct pci_dev *pdev) | |
| 1124 | +{ | |
| 1125 | + struct pvrdma_dev *dev = pci_get_drvdata(pdev); | |
| 1126 | + | |
| 1127 | + if (!dev) | |
| 1128 | + return; | |
| 1129 | + | |
| 1130 | + dev_info(&pdev->dev, "detaching from device\n"); | |
| 1131 | + | |
| 1132 | + unregister_netdevice_notifier(&dev->nb_netdev); | |
| 1133 | + dev->nb_netdev.notifier_call = NULL; | |
| 1134 | + | |
| 1135 | + flush_workqueue(event_wq); | |
| 1136 | + | |
| 1137 | + /* Unregister ib device */ | |
| 1138 | + ib_unregister_device(&dev->ib_dev); | |
| 1139 | + | |
| 1140 | + mutex_lock(&pvrdma_device_list_lock); | |
| 1141 | + list_del(&dev->device_link); | |
| 1142 | + mutex_unlock(&pvrdma_device_list_lock); | |
| 1143 | + | |
| 1144 | + pvrdma_disable_intrs(dev); | |
| 1145 | + pvrdma_free_irq(dev); | |
| 1146 | + pvrdma_disable_msi_all(dev); | |
| 1147 | + | |
| 1148 | + /* Deactivate pvrdma device */ | |
| 1149 | + pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_RESET); | |
| 1150 | + pvrdma_page_dir_cleanup(dev, &dev->cq_pdir); | |
| 1151 | + pvrdma_page_dir_cleanup(dev, &dev->async_pdir); | |
| 1152 | + pvrdma_free_slots(dev); | |
| 1153 | + | |
| 1154 | + iounmap(dev->regs); | |
| 1155 | + kfree(dev->sgid_tbl); | |
| 1156 | + kfree(dev->cq_tbl); | |
| 1157 | + kfree(dev->qp_tbl); | |
| 1158 | + pvrdma_uar_table_cleanup(dev); | |
| 1159 | + iounmap(dev->driver_uar.map); | |
| 1160 | + | |
| 1161 | + ib_dealloc_device(&dev->ib_dev); | |
| 1162 | + | |
| 1163 | + /* Free pci resources */ | |
| 1164 | + pci_release_regions(pdev); | |
| 1165 | + pci_disable_device(pdev); | |
| 1166 | + pci_set_drvdata(pdev, NULL); | |
| 1167 | +} | |
| 1168 | + | |
| 1169 | +static struct pci_device_id pvrdma_pci_table[] = { | |
| 1170 | + { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_PVRDMA), }, | |
| 1171 | + { 0 }, | |
| 1172 | +}; | |
| 1173 | + | |
| 1174 | +MODULE_DEVICE_TABLE(pci, pvrdma_pci_table); | |
| 1175 | + | |
| 1176 | +static struct pci_driver pvrdma_driver = { | |
| 1177 | + .name = DRV_NAME, | |
| 1178 | + .id_table = pvrdma_pci_table, | |
| 1179 | + .probe = pvrdma_pci_probe, | |
| 1180 | + .remove = pvrdma_pci_remove, | |
| 1181 | +}; | |
| 1182 | + | |
| 1183 | +static int __init pvrdma_init(void) | |
| 1184 | +{ | |
| 1185 | + int err; | |
| 1186 | + | |
| 1187 | + event_wq = alloc_ordered_workqueue("pvrdma_event_wq", WQ_MEM_RECLAIM); | |
| 1188 | + if (!event_wq) | |
| 1189 | + return -ENOMEM; | |
| 1190 | + | |
| 1191 | + err = pci_register_driver(&pvrdma_driver); | |
| 1192 | + if (err) | |
| 1193 | + destroy_workqueue(event_wq); | |
| 1194 | + | |
| 1195 | + return err; | |
| 1196 | +} | |
| 1197 | + | |
| 1198 | +static void __exit pvrdma_cleanup(void) | |
| 1199 | +{ | |
| 1200 | + pci_unregister_driver(&pvrdma_driver); | |
| 1201 | + | |
| 1202 | + destroy_workqueue(event_wq); | |
| 1203 | +} | |
| 1204 | + | |
| 1205 | +module_init(pvrdma_init); | |
| 1206 | +module_exit(pvrdma_cleanup); | |
| 1207 | + | |
| 1208 | +MODULE_AUTHOR("VMware, Inc"); | |
| 1209 | +MODULE_DESCRIPTION("VMware Paravirtual RDMA driver"); | |
| 1210 | +MODULE_VERSION(DRV_VERSION); | |
| 1211 | +MODULE_LICENSE("Dual BSD/GPL"); | |
| @@ -0,0 +1,304 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <linux/errno.h> | |
| 47 | +#include <linux/slab.h> | |
| 48 | +#include <linux/bitmap.h> | |
| 49 | + | |
| 50 | +#include "pvrdma.h" | |
| 51 | + | |
| 52 | +int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, | |
| 53 | + u64 npages, bool alloc_pages) | |
| 54 | +{ | |
| 55 | + u64 i; | |
| 56 | + | |
| 57 | + if (npages > PVRDMA_PAGE_DIR_MAX_PAGES) | |
| 58 | + return -EINVAL; | |
| 59 | + | |
| 60 | + memset(pdir, 0, sizeof(*pdir)); | |
| 61 | + | |
| 62 | + pdir->dir = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, | |
| 63 | + &pdir->dir_dma, GFP_KERNEL); | |
| 64 | + if (!pdir->dir) | |
| 65 | + goto err; | |
| 66 | + | |
| 67 | + pdir->ntables = PVRDMA_PAGE_DIR_TABLE(npages - 1) + 1; | |
| 68 | + pdir->tables = kcalloc(pdir->ntables, sizeof(*pdir->tables), | |
| 69 | + GFP_KERNEL); | |
| 70 | + if (!pdir->tables) | |
| 71 | + goto err; | |
| 72 | + | |
| 73 | + for (i = 0; i < pdir->ntables; i++) { | |
| 74 | + pdir->tables[i] = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, | |
| 75 | + (dma_addr_t *)&pdir->dir[i], | |
| 76 | + GFP_KERNEL); | |
| 77 | + if (!pdir->tables[i]) | |
| 78 | + goto err; | |
| 79 | + } | |
| 80 | + | |
| 81 | + pdir->npages = npages; | |
| 82 | + | |
| 83 | + if (alloc_pages) { | |
| 84 | + pdir->pages = kcalloc(npages, sizeof(*pdir->pages), | |
| 85 | + GFP_KERNEL); | |
| 86 | + if (!pdir->pages) | |
| 87 | + goto err; | |
| 88 | + | |
| 89 | + for (i = 0; i < pdir->npages; i++) { | |
| 90 | + dma_addr_t page_dma; | |
| 91 | + | |
| 92 | + pdir->pages[i] = dma_alloc_coherent(&dev->pdev->dev, | |
| 93 | + PAGE_SIZE, | |
| 94 | + &page_dma, | |
| 95 | + GFP_KERNEL); | |
| 96 | + if (!pdir->pages[i]) | |
| 97 | + goto err; | |
| 98 | + | |
| 99 | + pvrdma_page_dir_insert_dma(pdir, i, page_dma); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + return 0; | |
| 104 | + | |
| 105 | +err: | |
| 106 | + pvrdma_page_dir_cleanup(dev, pdir); | |
| 107 | + | |
| 108 | + return -ENOMEM; | |
| 109 | +} | |
| 110 | + | |
| 111 | +static u64 *pvrdma_page_dir_table(struct pvrdma_page_dir *pdir, u64 idx) | |
| 112 | +{ | |
| 113 | + return pdir->tables[PVRDMA_PAGE_DIR_TABLE(idx)]; | |
| 114 | +} | |
| 115 | + | |
| 116 | +dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx) | |
| 117 | +{ | |
| 118 | + return pvrdma_page_dir_table(pdir, idx)[PVRDMA_PAGE_DIR_PAGE(idx)]; | |
| 119 | +} | |
| 120 | + | |
| 121 | +static void pvrdma_page_dir_cleanup_pages(struct pvrdma_dev *dev, | |
| 122 | + struct pvrdma_page_dir *pdir) | |
| 123 | +{ | |
| 124 | + if (pdir->pages) { | |
| 125 | + u64 i; | |
| 126 | + | |
| 127 | + for (i = 0; i < pdir->npages && pdir->pages[i]; i++) { | |
| 128 | + dma_addr_t page_dma = pvrdma_page_dir_get_dma(pdir, i); | |
| 129 | + | |
| 130 | + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, | |
| 131 | + pdir->pages[i], page_dma); | |
| 132 | + } | |
| 133 | + | |
| 134 | + kfree(pdir->pages); | |
| 135 | + } | |
| 136 | +} | |
| 137 | + | |
| 138 | +static void pvrdma_page_dir_cleanup_tables(struct pvrdma_dev *dev, | |
| 139 | + struct pvrdma_page_dir *pdir) | |
| 140 | +{ | |
| 141 | + if (pdir->tables) { | |
| 142 | + int i; | |
| 143 | + | |
| 144 | + pvrdma_page_dir_cleanup_pages(dev, pdir); | |
| 145 | + | |
| 146 | + for (i = 0; i < pdir->ntables; i++) { | |
| 147 | + u64 *table = pdir->tables[i]; | |
| 148 | + | |
| 149 | + if (table) | |
| 150 | + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, | |
| 151 | + table, pdir->dir[i]); | |
| 152 | + } | |
| 153 | + | |
| 154 | + kfree(pdir->tables); | |
| 155 | + } | |
| 156 | +} | |
| 157 | + | |
| 158 | +void pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, | |
| 159 | + struct pvrdma_page_dir *pdir) | |
| 160 | +{ | |
| 161 | + if (pdir->dir) { | |
| 162 | + pvrdma_page_dir_cleanup_tables(dev, pdir); | |
| 163 | + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, | |
| 164 | + pdir->dir, pdir->dir_dma); | |
| 165 | + } | |
| 166 | +} | |
| 167 | + | |
| 168 | +int pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, | |
| 169 | + dma_addr_t daddr) | |
| 170 | +{ | |
| 171 | + u64 *table; | |
| 172 | + | |
| 173 | + if (idx >= pdir->npages) | |
| 174 | + return -EINVAL; | |
| 175 | + | |
| 176 | + table = pvrdma_page_dir_table(pdir, idx); | |
| 177 | + table[PVRDMA_PAGE_DIR_PAGE(idx)] = daddr; | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 182 | +int pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, | |
| 183 | + struct ib_umem *umem, u64 offset) | |
| 184 | +{ | |
| 185 | + u64 i = offset; | |
| 186 | + int j, entry; | |
| 187 | + int ret = 0, len = 0; | |
| 188 | + struct scatterlist *sg; | |
| 189 | + | |
| 190 | + if (offset >= pdir->npages) | |
| 191 | + return -EINVAL; | |
| 192 | + | |
| 193 | + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { | |
| 194 | + len = sg_dma_len(sg) >> PAGE_SHIFT; | |
| 195 | + for (j = 0; j < len; j++) { | |
| 196 | + dma_addr_t addr = sg_dma_address(sg) + | |
| 197 | + umem->page_size * j; | |
| 198 | + | |
| 199 | + ret = pvrdma_page_dir_insert_dma(pdir, i, addr); | |
| 200 | + if (ret) | |
| 201 | + goto exit; | |
| 202 | + | |
| 203 | + i++; | |
| 204 | + } | |
| 205 | + } | |
| 206 | + | |
| 207 | +exit: | |
| 208 | + return ret; | |
| 209 | +} | |
| 210 | + | |
| 211 | +int pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, | |
| 212 | + u64 *page_list, | |
| 213 | + int num_pages) | |
| 214 | +{ | |
| 215 | + int i; | |
| 216 | + int ret; | |
| 217 | + | |
| 218 | + if (num_pages > pdir->npages) | |
| 219 | + return -EINVAL; | |
| 220 | + | |
| 221 | + for (i = 0; i < num_pages; i++) { | |
| 222 | + ret = pvrdma_page_dir_insert_dma(pdir, i, page_list[i]); | |
| 223 | + if (ret) | |
| 224 | + return ret; | |
| 225 | + } | |
| 226 | + | |
| 227 | + return 0; | |
| 228 | +} | |
| 229 | + | |
| 230 | +void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, const struct pvrdma_qp_cap *src) | |
| 231 | +{ | |
| 232 | + dst->max_send_wr = src->max_send_wr; | |
| 233 | + dst->max_recv_wr = src->max_recv_wr; | |
| 234 | + dst->max_send_sge = src->max_send_sge; | |
| 235 | + dst->max_recv_sge = src->max_recv_sge; | |
| 236 | + dst->max_inline_data = src->max_inline_data; | |
| 237 | +} | |
| 238 | + | |
| 239 | +void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, const struct ib_qp_cap *src) | |
| 240 | +{ | |
| 241 | + dst->max_send_wr = src->max_send_wr; | |
| 242 | + dst->max_recv_wr = src->max_recv_wr; | |
| 243 | + dst->max_send_sge = src->max_send_sge; | |
| 244 | + dst->max_recv_sge = src->max_recv_sge; | |
| 245 | + dst->max_inline_data = src->max_inline_data; | |
| 246 | +} | |
| 247 | + | |
| 248 | +void pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src) | |
| 249 | +{ | |
| 250 | + BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); | |
| 251 | + memcpy(dst, src, sizeof(*src)); | |
| 252 | +} | |
| 253 | + | |
| 254 | +void ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src) | |
| 255 | +{ | |
| 256 | + BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); | |
| 257 | + memcpy(dst, src, sizeof(*src)); | |
| 258 | +} | |
| 259 | + | |
| 260 | +void pvrdma_global_route_to_ib(struct ib_global_route *dst, | |
| 261 | + const struct pvrdma_global_route *src) | |
| 262 | +{ | |
| 263 | + pvrdma_gid_to_ib(&dst->dgid, &src->dgid); | |
| 264 | + dst->flow_label = src->flow_label; | |
| 265 | + dst->sgid_index = src->sgid_index; | |
| 266 | + dst->hop_limit = src->hop_limit; | |
| 267 | + dst->traffic_class = src->traffic_class; | |
| 268 | +} | |
| 269 | + | |
| 270 | +void ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, | |
| 271 | + const struct ib_global_route *src) | |
| 272 | +{ | |
| 273 | + ib_gid_to_pvrdma(&dst->dgid, &src->dgid); | |
| 274 | + dst->flow_label = src->flow_label; | |
| 275 | + dst->sgid_index = src->sgid_index; | |
| 276 | + dst->hop_limit = src->hop_limit; | |
| 277 | + dst->traffic_class = src->traffic_class; | |
| 278 | +} | |
| 279 | + | |
| 280 | +void pvrdma_ah_attr_to_ib(struct ib_ah_attr *dst, | |
| 281 | + const struct pvrdma_ah_attr *src) | |
| 282 | +{ | |
| 283 | + pvrdma_global_route_to_ib(&dst->grh, &src->grh); | |
| 284 | + dst->dlid = src->dlid; | |
| 285 | + dst->sl = src->sl; | |
| 286 | + dst->src_path_bits = src->src_path_bits; | |
| 287 | + dst->static_rate = src->static_rate; | |
| 288 | + dst->ah_flags = src->ah_flags; | |
| 289 | + dst->port_num = src->port_num; | |
| 290 | + memcpy(&dst->dmac, &src->dmac, sizeof(dst->dmac)); | |
| 291 | +} | |
| 292 | + | |
| 293 | +void ib_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, | |
| 294 | + const struct ib_ah_attr *src) | |
| 295 | +{ | |
| 296 | + ib_global_route_to_pvrdma(&dst->grh, &src->grh); | |
| 297 | + dst->dlid = src->dlid; | |
| 298 | + dst->sl = src->sl; | |
| 299 | + dst->src_path_bits = src->src_path_bits; | |
| 300 | + dst->static_rate = src->static_rate; | |
| 301 | + dst->ah_flags = src->ah_flags; | |
| 302 | + dst->port_num = src->port_num; | |
| 303 | + memcpy(&dst->dmac, &src->dmac, sizeof(dst->dmac)); | |
| 304 | +} | |
| @@ -0,0 +1,334 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <linux/list.h> | |
| 47 | +#include <linux/slab.h> | |
| 48 | + | |
| 49 | +#include "pvrdma.h" | |
| 50 | + | |
| 51 | +/** | |
| 52 | + * pvrdma_get_dma_mr - get a DMA memory region | |
| 53 | + * @pd: protection domain | |
| 54 | + * @acc: access flags | |
| 55 | + * | |
| 56 | + * @return: ib_mr pointer on success, otherwise returns an errno. | |
| 57 | + */ | |
| 58 | +struct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc) | |
| 59 | +{ | |
| 60 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 61 | + struct pvrdma_user_mr *mr; | |
| 62 | + union pvrdma_cmd_req req; | |
| 63 | + union pvrdma_cmd_resp rsp; | |
| 64 | + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; | |
| 65 | + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; | |
| 66 | + int ret; | |
| 67 | + | |
| 68 | + /* Support only LOCAL_WRITE flag for DMA MRs */ | |
| 69 | + if (acc & ~IB_ACCESS_LOCAL_WRITE) { | |
| 70 | + dev_warn(&dev->pdev->dev, | |
| 71 | + "unsupported dma mr access flags %#x\n", acc); | |
| 72 | + return ERR_PTR(-EOPNOTSUPP); | |
| 73 | + } | |
| 74 | + | |
| 75 | + mr = kzalloc(sizeof(*mr), GFP_KERNEL); | |
| 76 | + if (!mr) | |
| 77 | + return ERR_PTR(-ENOMEM); | |
| 78 | + | |
| 79 | + memset(cmd, 0, sizeof(*cmd)); | |
| 80 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; | |
| 81 | + cmd->pd_handle = to_vpd(pd)->pd_handle; | |
| 82 | + cmd->access_flags = acc; | |
| 83 | + cmd->flags = PVRDMA_MR_FLAG_DMA; | |
| 84 | + | |
| 85 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); | |
| 86 | + if (ret < 0) { | |
| 87 | + dev_warn(&dev->pdev->dev, | |
| 88 | + "could not get DMA mem region, error: %d\n", ret); | |
| 89 | + kfree(mr); | |
| 90 | + return ERR_PTR(ret); | |
| 91 | + } | |
| 92 | + | |
| 93 | + mr->mmr.mr_handle = resp->mr_handle; | |
| 94 | + mr->ibmr.lkey = resp->lkey; | |
| 95 | + mr->ibmr.rkey = resp->rkey; | |
| 96 | + | |
| 97 | + return &mr->ibmr; | |
| 98 | +} | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * pvrdma_reg_user_mr - register a userspace memory region | |
| 102 | + * @pd: protection domain | |
| 103 | + * @start: starting address | |
| 104 | + * @length: length of region | |
| 105 | + * @virt_addr: I/O virtual address | |
| 106 | + * @access_flags: access flags for memory region | |
| 107 | + * @udata: user data | |
| 108 | + * | |
| 109 | + * @return: ib_mr pointer on success, otherwise returns an errno. | |
| 110 | + */ | |
| 111 | +struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, | |
| 112 | + u64 virt_addr, int access_flags, | |
| 113 | + struct ib_udata *udata) | |
| 114 | +{ | |
| 115 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 116 | + struct pvrdma_user_mr *mr = NULL; | |
| 117 | + struct ib_umem *umem; | |
| 118 | + union pvrdma_cmd_req req; | |
| 119 | + union pvrdma_cmd_resp rsp; | |
| 120 | + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; | |
| 121 | + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; | |
| 122 | + int nchunks; | |
| 123 | + int ret; | |
| 124 | + int entry; | |
| 125 | + struct scatterlist *sg; | |
| 126 | + | |
| 127 | + if (length == 0 || length > dev->dsr->caps.max_mr_size) { | |
| 128 | + dev_warn(&dev->pdev->dev, "invalid mem region length\n"); | |
| 129 | + return ERR_PTR(-EINVAL); | |
| 130 | + } | |
| 131 | + | |
| 132 | + umem = ib_umem_get(pd->uobject->context, start, | |
| 133 | + length, access_flags, 0); | |
| 134 | + if (IS_ERR(umem)) { | |
| 135 | + dev_warn(&dev->pdev->dev, | |
| 136 | + "could not get umem for mem region\n"); | |
| 137 | + return ERR_CAST(umem); | |
| 138 | + } | |
| 139 | + | |
| 140 | + nchunks = 0; | |
| 141 | + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) | |
| 142 | + nchunks += sg_dma_len(sg) >> PAGE_SHIFT; | |
| 143 | + | |
| 144 | + if (nchunks < 0 || nchunks > PVRDMA_PAGE_DIR_MAX_PAGES) { | |
| 145 | + dev_warn(&dev->pdev->dev, "overflow %d pages in mem region\n", | |
| 146 | + nchunks); | |
| 147 | + ret = -EINVAL; | |
| 148 | + goto err_umem; | |
| 149 | + } | |
| 150 | + | |
| 151 | + mr = kzalloc(sizeof(*mr), GFP_KERNEL); | |
| 152 | + if (!mr) { | |
| 153 | + ret = -ENOMEM; | |
| 154 | + goto err_umem; | |
| 155 | + } | |
| 156 | + | |
| 157 | + mr->mmr.iova = virt_addr; | |
| 158 | + mr->mmr.size = length; | |
| 159 | + mr->umem = umem; | |
| 160 | + | |
| 161 | + ret = pvrdma_page_dir_init(dev, &mr->pdir, nchunks, false); | |
| 162 | + if (ret) { | |
| 163 | + dev_warn(&dev->pdev->dev, | |
| 164 | + "could not allocate page directory\n"); | |
| 165 | + goto err_umem; | |
| 166 | + } | |
| 167 | + | |
| 168 | + ret = pvrdma_page_dir_insert_umem(&mr->pdir, mr->umem, 0); | |
| 169 | + if (ret) | |
| 170 | + goto err_pdir; | |
| 171 | + | |
| 172 | + memset(cmd, 0, sizeof(*cmd)); | |
| 173 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; | |
| 174 | + cmd->start = start; | |
| 175 | + cmd->length = length; | |
| 176 | + cmd->pd_handle = to_vpd(pd)->pd_handle; | |
| 177 | + cmd->access_flags = access_flags; | |
| 178 | + cmd->nchunks = nchunks; | |
| 179 | + cmd->pdir_dma = mr->pdir.dir_dma; | |
| 180 | + | |
| 181 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); | |
| 182 | + if (ret < 0) { | |
| 183 | + dev_warn(&dev->pdev->dev, | |
| 184 | + "could not register mem region, error: %d\n", ret); | |
| 185 | + goto err_pdir; | |
| 186 | + } | |
| 187 | + | |
| 188 | + mr->mmr.mr_handle = resp->mr_handle; | |
| 189 | + mr->ibmr.lkey = resp->lkey; | |
| 190 | + mr->ibmr.rkey = resp->rkey; | |
| 191 | + | |
| 192 | + return &mr->ibmr; | |
| 193 | + | |
| 194 | +err_pdir: | |
| 195 | + pvrdma_page_dir_cleanup(dev, &mr->pdir); | |
| 196 | +err_umem: | |
| 197 | + ib_umem_release(umem); | |
| 198 | + kfree(mr); | |
| 199 | + | |
| 200 | + return ERR_PTR(ret); | |
| 201 | +} | |
| 202 | + | |
| 203 | +/** | |
| 204 | + * pvrdma_alloc_mr - allocate a memory region | |
| 205 | + * @pd: protection domain | |
| 206 | + * @mr_type: type of memory region | |
| 207 | + * @max_num_sg: maximum number of pages | |
| 208 | + * | |
| 209 | + * @return: ib_mr pointer on success, otherwise returns an errno. | |
| 210 | + */ | |
| 211 | +struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, | |
| 212 | + u32 max_num_sg) | |
| 213 | +{ | |
| 214 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 215 | + struct pvrdma_user_mr *mr; | |
| 216 | + union pvrdma_cmd_req req; | |
| 217 | + union pvrdma_cmd_resp rsp; | |
| 218 | + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; | |
| 219 | + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; | |
| 220 | + int size = max_num_sg * sizeof(u64); | |
| 221 | + int ret; | |
| 222 | + | |
| 223 | + if (mr_type != IB_MR_TYPE_MEM_REG || | |
| 224 | + max_num_sg > PVRDMA_MAX_FAST_REG_PAGES) | |
| 225 | + return ERR_PTR(-EINVAL); | |
| 226 | + | |
| 227 | + mr = kzalloc(sizeof(*mr), GFP_KERNEL); | |
| 228 | + if (!mr) | |
| 229 | + return ERR_PTR(-ENOMEM); | |
| 230 | + | |
| 231 | + mr->pages = kzalloc(size, GFP_KERNEL); | |
| 232 | + if (!mr->pages) { | |
| 233 | + ret = -ENOMEM; | |
| 234 | + goto freemr; | |
| 235 | + } | |
| 236 | + | |
| 237 | + ret = pvrdma_page_dir_init(dev, &mr->pdir, max_num_sg, false); | |
| 238 | + if (ret) { | |
| 239 | + dev_warn(&dev->pdev->dev, | |
| 240 | + "failed to allocate page dir for mr\n"); | |
| 241 | + ret = -ENOMEM; | |
| 242 | + goto freepages; | |
| 243 | + } | |
| 244 | + | |
| 245 | + memset(cmd, 0, sizeof(*cmd)); | |
| 246 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; | |
| 247 | + cmd->pd_handle = to_vpd(pd)->pd_handle; | |
| 248 | + cmd->access_flags = 0; | |
| 249 | + cmd->flags = PVRDMA_MR_FLAG_FRMR; | |
| 250 | + cmd->nchunks = max_num_sg; | |
| 251 | + | |
| 252 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); | |
| 253 | + if (ret < 0) { | |
| 254 | + dev_warn(&dev->pdev->dev, | |
| 255 | + "could not create FR mem region, error: %d\n", ret); | |
| 256 | + goto freepdir; | |
| 257 | + } | |
| 258 | + | |
| 259 | + mr->max_pages = max_num_sg; | |
| 260 | + mr->mmr.mr_handle = resp->mr_handle; | |
| 261 | + mr->ibmr.lkey = resp->lkey; | |
| 262 | + mr->ibmr.rkey = resp->rkey; | |
| 263 | + mr->page_shift = PAGE_SHIFT; | |
| 264 | + mr->umem = NULL; | |
| 265 | + | |
| 266 | + return &mr->ibmr; | |
| 267 | + | |
| 268 | +freepdir: | |
| 269 | + pvrdma_page_dir_cleanup(dev, &mr->pdir); | |
| 270 | +freepages: | |
| 271 | + kfree(mr->pages); | |
| 272 | +freemr: | |
| 273 | + kfree(mr); | |
| 274 | + return ERR_PTR(ret); | |
| 275 | +} | |
| 276 | + | |
| 277 | +/** | |
| 278 | + * pvrdma_dereg_mr - deregister a memory region | |
| 279 | + * @ibmr: memory region | |
| 280 | + * | |
| 281 | + * @return: 0 on success. | |
| 282 | + */ | |
| 283 | +int pvrdma_dereg_mr(struct ib_mr *ibmr) | |
| 284 | +{ | |
| 285 | + struct pvrdma_user_mr *mr = to_vmr(ibmr); | |
| 286 | + struct pvrdma_dev *dev = to_vdev(ibmr->device); | |
| 287 | + union pvrdma_cmd_req req; | |
| 288 | + struct pvrdma_cmd_destroy_mr *cmd = &req.destroy_mr; | |
| 289 | + int ret; | |
| 290 | + | |
| 291 | + memset(cmd, 0, sizeof(*cmd)); | |
| 292 | + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_MR; | |
| 293 | + cmd->mr_handle = mr->mmr.mr_handle; | |
| 294 | + ret = pvrdma_cmd_post(dev, &req, NULL, 0); | |
| 295 | + if (ret < 0) | |
| 296 | + dev_warn(&dev->pdev->dev, | |
| 297 | + "could not deregister mem region, error: %d\n", ret); | |
| 298 | + | |
| 299 | + pvrdma_page_dir_cleanup(dev, &mr->pdir); | |
| 300 | + if (mr->umem) | |
| 301 | + ib_umem_release(mr->umem); | |
| 302 | + | |
| 303 | + kfree(mr->pages); | |
| 304 | + kfree(mr); | |
| 305 | + | |
| 306 | + return 0; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static int pvrdma_set_page(struct ib_mr *ibmr, u64 addr) | |
| 310 | +{ | |
| 311 | + struct pvrdma_user_mr *mr = to_vmr(ibmr); | |
| 312 | + | |
| 313 | + if (mr->npages == mr->max_pages) | |
| 314 | + return -ENOMEM; | |
| 315 | + | |
| 316 | + mr->pages[mr->npages++] = addr; | |
| 317 | + return 0; | |
| 318 | +} | |
| 319 | + | |
| 320 | +int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, | |
| 321 | + unsigned int *sg_offset) | |
| 322 | +{ | |
| 323 | + struct pvrdma_user_mr *mr = to_vmr(ibmr); | |
| 324 | + struct pvrdma_dev *dev = to_vdev(ibmr->device); | |
| 325 | + int ret; | |
| 326 | + | |
| 327 | + mr->npages = 0; | |
| 328 | + | |
| 329 | + ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, pvrdma_set_page); | |
| 330 | + if (ret < 0) | |
| 331 | + dev_warn(&dev->pdev->dev, "could not map sg to pages\n"); | |
| 332 | + | |
| 333 | + return ret; | |
| 334 | +} | |
| @@ -0,0 +1,972 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <asm/page.h> | |
| 47 | +#include <linux/io.h> | |
| 48 | +#include <linux/wait.h> | |
| 49 | +#include <rdma/ib_addr.h> | |
| 50 | +#include <rdma/ib_smi.h> | |
| 51 | +#include <rdma/ib_user_verbs.h> | |
| 52 | + | |
| 53 | +#include "pvrdma.h" | |
| 54 | + | |
| 55 | +static inline void get_cqs(struct pvrdma_qp *qp, struct pvrdma_cq **send_cq, | |
| 56 | + struct pvrdma_cq **recv_cq) | |
| 57 | +{ | |
| 58 | + *send_cq = to_vcq(qp->ibqp.send_cq); | |
| 59 | + *recv_cq = to_vcq(qp->ibqp.recv_cq); | |
| 60 | +} | |
| 61 | + | |
| 62 | +static void pvrdma_lock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, | |
| 63 | + unsigned long *scq_flags, | |
| 64 | + unsigned long *rcq_flags) | |
| 65 | + __acquires(scq->cq_lock) __acquires(rcq->cq_lock) | |
| 66 | +{ | |
| 67 | + if (scq == rcq) { | |
| 68 | + spin_lock_irqsave(&scq->cq_lock, *scq_flags); | |
| 69 | + __acquire(rcq->cq_lock); | |
| 70 | + } else if (scq->cq_handle < rcq->cq_handle) { | |
| 71 | + spin_lock_irqsave(&scq->cq_lock, *scq_flags); | |
| 72 | + spin_lock_irqsave_nested(&rcq->cq_lock, *rcq_flags, | |
| 73 | + SINGLE_DEPTH_NESTING); | |
| 74 | + } else { | |
| 75 | + spin_lock_irqsave(&rcq->cq_lock, *rcq_flags); | |
| 76 | + spin_lock_irqsave_nested(&scq->cq_lock, *scq_flags, | |
| 77 | + SINGLE_DEPTH_NESTING); | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void pvrdma_unlock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, | |
| 82 | + unsigned long *scq_flags, | |
| 83 | + unsigned long *rcq_flags) | |
| 84 | + __releases(scq->cq_lock) __releases(rcq->cq_lock) | |
| 85 | +{ | |
| 86 | + if (scq == rcq) { | |
| 87 | + __release(rcq->cq_lock); | |
| 88 | + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); | |
| 89 | + } else if (scq->cq_handle < rcq->cq_handle) { | |
| 90 | + spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); | |
| 91 | + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); | |
| 92 | + } else { | |
| 93 | + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); | |
| 94 | + spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); | |
| 95 | + } | |
| 96 | +} | |
| 97 | + | |
| 98 | +static void pvrdma_reset_qp(struct pvrdma_qp *qp) | |
| 99 | +{ | |
| 100 | + struct pvrdma_cq *scq, *rcq; | |
| 101 | + unsigned long scq_flags, rcq_flags; | |
| 102 | + | |
| 103 | + /* Clean up cqes */ | |
| 104 | + get_cqs(qp, &scq, &rcq); | |
| 105 | + pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); | |
| 106 | + | |
| 107 | + _pvrdma_flush_cqe(qp, scq); | |
| 108 | + if (scq != rcq) | |
| 109 | + _pvrdma_flush_cqe(qp, rcq); | |
| 110 | + | |
| 111 | + pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); | |
| 112 | + | |
| 113 | + /* | |
| 114 | + * Reset queuepair. The checks are because usermode queuepairs won't | |
| 115 | + * have kernel ringstates. | |
| 116 | + */ | |
| 117 | + if (qp->rq.ring) { | |
| 118 | + atomic_set(&qp->rq.ring->cons_head, 0); | |
| 119 | + atomic_set(&qp->rq.ring->prod_tail, 0); | |
| 120 | + } | |
| 121 | + if (qp->sq.ring) { | |
| 122 | + atomic_set(&qp->sq.ring->cons_head, 0); | |
| 123 | + atomic_set(&qp->sq.ring->prod_tail, 0); | |
| 124 | + } | |
| 125 | +} | |
| 126 | + | |
| 127 | +static int pvrdma_set_rq_size(struct pvrdma_dev *dev, | |
| 128 | + struct ib_qp_cap *req_cap, | |
| 129 | + struct pvrdma_qp *qp) | |
| 130 | +{ | |
| 131 | + if (req_cap->max_recv_wr > dev->dsr->caps.max_qp_wr || | |
| 132 | + req_cap->max_recv_sge > dev->dsr->caps.max_sge) { | |
| 133 | + dev_warn(&dev->pdev->dev, "recv queue size invalid\n"); | |
| 134 | + return -EINVAL; | |
| 135 | + } | |
| 136 | + | |
| 137 | + qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_recv_wr)); | |
| 138 | + qp->rq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_recv_sge)); | |
| 139 | + | |
| 140 | + /* Write back */ | |
| 141 | + req_cap->max_recv_wr = qp->rq.wqe_cnt; | |
| 142 | + req_cap->max_recv_sge = qp->rq.max_sg; | |
| 143 | + | |
| 144 | + qp->rq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_rq_wqe_hdr) + | |
| 145 | + sizeof(struct pvrdma_sge) * | |
| 146 | + qp->rq.max_sg); | |
| 147 | + qp->npages_recv = (qp->rq.wqe_cnt * qp->rq.wqe_size + PAGE_SIZE - 1) / | |
| 148 | + PAGE_SIZE; | |
| 149 | + | |
| 150 | + return 0; | |
| 151 | +} | |
| 152 | + | |
| 153 | +static int pvrdma_set_sq_size(struct pvrdma_dev *dev, struct ib_qp_cap *req_cap, | |
| 154 | + enum ib_qp_type type, struct pvrdma_qp *qp) | |
| 155 | +{ | |
| 156 | + if (req_cap->max_send_wr > dev->dsr->caps.max_qp_wr || | |
| 157 | + req_cap->max_send_sge > dev->dsr->caps.max_sge) { | |
| 158 | + dev_warn(&dev->pdev->dev, "send queue size invalid\n"); | |
| 159 | + return -EINVAL; | |
| 160 | + } | |
| 161 | + | |
| 162 | + qp->sq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_send_wr)); | |
| 163 | + qp->sq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_send_sge)); | |
| 164 | + | |
| 165 | + /* Write back */ | |
| 166 | + req_cap->max_send_wr = qp->sq.wqe_cnt; | |
| 167 | + req_cap->max_send_sge = qp->sq.max_sg; | |
| 168 | + | |
| 169 | + qp->sq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_sq_wqe_hdr) + | |
| 170 | + sizeof(struct pvrdma_sge) * | |
| 171 | + qp->sq.max_sg); | |
| 172 | + /* Note: one extra page for the header. */ | |
| 173 | + qp->npages_send = 1 + (qp->sq.wqe_cnt * qp->sq.wqe_size + | |
| 174 | + PAGE_SIZE - 1) / PAGE_SIZE; | |
| 175 | + | |
| 176 | + return 0; | |
| 177 | +} | |
| 178 | + | |
| 179 | +/** | |
| 180 | + * pvrdma_create_qp - create queue pair | |
| 181 | + * @pd: protection domain | |
| 182 | + * @init_attr: queue pair attributes | |
| 183 | + * @udata: user data | |
| 184 | + * | |
| 185 | + * @return: the ib_qp pointer on success, otherwise returns an errno. | |
| 186 | + */ | |
| 187 | +struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, | |
| 188 | + struct ib_qp_init_attr *init_attr, | |
| 189 | + struct ib_udata *udata) | |
| 190 | +{ | |
| 191 | + struct pvrdma_qp *qp = NULL; | |
| 192 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 193 | + union pvrdma_cmd_req req; | |
| 194 | + union pvrdma_cmd_resp rsp; | |
| 195 | + struct pvrdma_cmd_create_qp *cmd = &req.create_qp; | |
| 196 | + struct pvrdma_cmd_create_qp_resp *resp = &rsp.create_qp_resp; | |
| 197 | + struct pvrdma_create_qp ucmd; | |
| 198 | + unsigned long flags; | |
| 199 | + int ret; | |
| 200 | + | |
| 201 | + if (init_attr->create_flags) { | |
| 202 | + dev_warn(&dev->pdev->dev, | |
| 203 | + "invalid create queuepair flags %#x\n", | |
| 204 | + init_attr->create_flags); | |
| 205 | + return ERR_PTR(-EINVAL); | |
| 206 | + } | |
| 207 | + | |
| 208 | + if (init_attr->qp_type != IB_QPT_RC && | |
| 209 | + init_attr->qp_type != IB_QPT_UD && | |
| 210 | + init_attr->qp_type != IB_QPT_GSI) { | |
| 211 | + dev_warn(&dev->pdev->dev, "queuepair type %d not supported\n", | |
| 212 | + init_attr->qp_type); | |
| 213 | + return ERR_PTR(-EINVAL); | |
| 214 | + } | |
| 215 | + | |
| 216 | + if (!atomic_add_unless(&dev->num_qps, 1, dev->dsr->caps.max_qp)) | |
| 217 | + return ERR_PTR(-ENOMEM); | |
| 218 | + | |
| 219 | + switch (init_attr->qp_type) { | |
| 220 | + case IB_QPT_GSI: | |
| 221 | + if (init_attr->port_num == 0 || | |
| 222 | + init_attr->port_num > pd->device->phys_port_cnt || | |
| 223 | + udata) { | |
| 224 | + dev_warn(&dev->pdev->dev, "invalid queuepair attrs\n"); | |
| 225 | + ret = -EINVAL; | |
| 226 | + goto err_qp; | |
| 227 | + } | |
| 228 | + /* fall through */ | |
| 229 | + case IB_QPT_RC: | |
| 230 | + case IB_QPT_UD: | |
| 231 | + qp = kzalloc(sizeof(*qp), GFP_KERNEL); | |
| 232 | + if (!qp) { | |
| 233 | + ret = -ENOMEM; | |
| 234 | + goto err_qp; | |
| 235 | + } | |
| 236 | + | |
| 237 | + spin_lock_init(&qp->sq.lock); | |
| 238 | + spin_lock_init(&qp->rq.lock); | |
| 239 | + mutex_init(&qp->mutex); | |
| 240 | + atomic_set(&qp->refcnt, 1); | |
| 241 | + init_waitqueue_head(&qp->wait); | |
| 242 | + | |
| 243 | + qp->state = IB_QPS_RESET; | |
| 244 | + | |
| 245 | + if (pd->uobject && udata) { | |
| 246 | + dev_dbg(&dev->pdev->dev, | |
| 247 | + "create queuepair from user space\n"); | |
| 248 | + | |
| 249 | + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { | |
| 250 | + ret = -EFAULT; | |
| 251 | + goto err_qp; | |
| 252 | + } | |
| 253 | + | |
| 254 | + /* set qp->sq.wqe_cnt, shift, buf_size.. */ | |
| 255 | + qp->rumem = ib_umem_get(pd->uobject->context, | |
| 256 | + ucmd.rbuf_addr, | |
| 257 | + ucmd.rbuf_size, 0, 0); | |
| 258 | + if (IS_ERR(qp->rumem)) { | |
| 259 | + ret = PTR_ERR(qp->rumem); | |
| 260 | + goto err_qp; | |
| 261 | + } | |
| 262 | + | |
| 263 | + qp->sumem = ib_umem_get(pd->uobject->context, | |
| 264 | + ucmd.sbuf_addr, | |
| 265 | + ucmd.sbuf_size, 0, 0); | |
| 266 | + if (IS_ERR(qp->sumem)) { | |
| 267 | + ib_umem_release(qp->rumem); | |
| 268 | + ret = PTR_ERR(qp->sumem); | |
| 269 | + goto err_qp; | |
| 270 | + } | |
| 271 | + | |
| 272 | + qp->npages_send = ib_umem_page_count(qp->sumem); | |
| 273 | + qp->npages_recv = ib_umem_page_count(qp->rumem); | |
| 274 | + qp->npages = qp->npages_send + qp->npages_recv; | |
| 275 | + } else { | |
| 276 | + qp->is_kernel = true; | |
| 277 | + | |
| 278 | + ret = pvrdma_set_sq_size(to_vdev(pd->device), | |
| 279 | + &init_attr->cap, | |
| 280 | + init_attr->qp_type, qp); | |
| 281 | + if (ret) | |
| 282 | + goto err_qp; | |
| 283 | + | |
| 284 | + ret = pvrdma_set_rq_size(to_vdev(pd->device), | |
| 285 | + &init_attr->cap, qp); | |
| 286 | + if (ret) | |
| 287 | + goto err_qp; | |
| 288 | + | |
| 289 | + qp->npages = qp->npages_send + qp->npages_recv; | |
| 290 | + | |
| 291 | + /* Skip header page. */ | |
| 292 | + qp->sq.offset = PAGE_SIZE; | |
| 293 | + | |
| 294 | + /* Recv queue pages are after send pages. */ | |
| 295 | + qp->rq.offset = qp->npages_send * PAGE_SIZE; | |
| 296 | + } | |
| 297 | + | |
| 298 | + if (qp->npages < 0 || qp->npages > PVRDMA_PAGE_DIR_MAX_PAGES) { | |
| 299 | + dev_warn(&dev->pdev->dev, | |
| 300 | + "overflow pages in queuepair\n"); | |
| 301 | + ret = -EINVAL; | |
| 302 | + goto err_umem; | |
| 303 | + } | |
| 304 | + | |
| 305 | + ret = pvrdma_page_dir_init(dev, &qp->pdir, qp->npages, | |
| 306 | + qp->is_kernel); | |
| 307 | + if (ret) { | |
| 308 | + dev_warn(&dev->pdev->dev, | |
| 309 | + "could not allocate page directory\n"); | |
| 310 | + goto err_umem; | |
| 311 | + } | |
| 312 | + | |
| 313 | + if (!qp->is_kernel) { | |
| 314 | + pvrdma_page_dir_insert_umem(&qp->pdir, qp->sumem, 0); | |
| 315 | + pvrdma_page_dir_insert_umem(&qp->pdir, qp->rumem, | |
| 316 | + qp->npages_send); | |
| 317 | + } else { | |
| 318 | + /* Ring state is always the first page. */ | |
| 319 | + qp->sq.ring = qp->pdir.pages[0]; | |
| 320 | + qp->rq.ring = &qp->sq.ring[1]; | |
| 321 | + } | |
| 322 | + break; | |
| 323 | + default: | |
| 324 | + ret = -EINVAL; | |
| 325 | + goto err_qp; | |
| 326 | + } | |
| 327 | + | |
| 328 | + /* Not supported */ | |
| 329 | + init_attr->cap.max_inline_data = 0; | |
| 330 | + | |
| 331 | + memset(cmd, 0, sizeof(*cmd)); | |
| 332 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_QP; | |
| 333 | + cmd->pd_handle = to_vpd(pd)->pd_handle; | |
| 334 | + cmd->send_cq_handle = to_vcq(init_attr->send_cq)->cq_handle; | |
| 335 | + cmd->recv_cq_handle = to_vcq(init_attr->recv_cq)->cq_handle; | |
| 336 | + cmd->max_send_wr = init_attr->cap.max_send_wr; | |
| 337 | + cmd->max_recv_wr = init_attr->cap.max_recv_wr; | |
| 338 | + cmd->max_send_sge = init_attr->cap.max_send_sge; | |
| 339 | + cmd->max_recv_sge = init_attr->cap.max_recv_sge; | |
| 340 | + cmd->max_inline_data = init_attr->cap.max_inline_data; | |
| 341 | + cmd->sq_sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; | |
| 342 | + cmd->qp_type = ib_qp_type_to_pvrdma(init_attr->qp_type); | |
| 343 | + cmd->access_flags = IB_ACCESS_LOCAL_WRITE; | |
| 344 | + cmd->total_chunks = qp->npages; | |
| 345 | + cmd->send_chunks = qp->npages_send - 1; | |
| 346 | + cmd->pdir_dma = qp->pdir.dir_dma; | |
| 347 | + | |
| 348 | + dev_dbg(&dev->pdev->dev, "create queuepair with %d, %d, %d, %d\n", | |
| 349 | + cmd->max_send_wr, cmd->max_recv_wr, cmd->max_send_sge, | |
| 350 | + cmd->max_recv_sge); | |
| 351 | + | |
| 352 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_QP_RESP); | |
| 353 | + if (ret < 0) { | |
| 354 | + dev_warn(&dev->pdev->dev, | |
| 355 | + "could not create queuepair, error: %d\n", ret); | |
| 356 | + goto err_pdir; | |
| 357 | + } | |
| 358 | + | |
| 359 | + /* max_send_wr/_recv_wr/_send_sge/_recv_sge/_inline_data */ | |
| 360 | + qp->qp_handle = resp->qpn; | |
| 361 | + qp->port = init_attr->port_num; | |
| 362 | + qp->ibqp.qp_num = resp->qpn; | |
| 363 | + spin_lock_irqsave(&dev->qp_tbl_lock, flags); | |
| 364 | + dev->qp_tbl[qp->qp_handle % dev->dsr->caps.max_qp] = qp; | |
| 365 | + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); | |
| 366 | + | |
| 367 | + return &qp->ibqp; | |
| 368 | + | |
| 369 | +err_pdir: | |
| 370 | + pvrdma_page_dir_cleanup(dev, &qp->pdir); | |
| 371 | +err_umem: | |
| 372 | + if (pd->uobject && udata) { | |
| 373 | + if (qp->rumem) | |
| 374 | + ib_umem_release(qp->rumem); | |
| 375 | + if (qp->sumem) | |
| 376 | + ib_umem_release(qp->sumem); | |
| 377 | + } | |
| 378 | +err_qp: | |
| 379 | + kfree(qp); | |
| 380 | + atomic_dec(&dev->num_qps); | |
| 381 | + | |
| 382 | + return ERR_PTR(ret); | |
| 383 | +} | |
| 384 | + | |
| 385 | +static void pvrdma_free_qp(struct pvrdma_qp *qp) | |
| 386 | +{ | |
| 387 | + struct pvrdma_dev *dev = to_vdev(qp->ibqp.device); | |
| 388 | + struct pvrdma_cq *scq; | |
| 389 | + struct pvrdma_cq *rcq; | |
| 390 | + unsigned long flags, scq_flags, rcq_flags; | |
| 391 | + | |
| 392 | + /* In case cq is polling */ | |
| 393 | + get_cqs(qp, &scq, &rcq); | |
| 394 | + pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); | |
| 395 | + | |
| 396 | + _pvrdma_flush_cqe(qp, scq); | |
| 397 | + if (scq != rcq) | |
| 398 | + _pvrdma_flush_cqe(qp, rcq); | |
| 399 | + | |
| 400 | + spin_lock_irqsave(&dev->qp_tbl_lock, flags); | |
| 401 | + dev->qp_tbl[qp->qp_handle] = NULL; | |
| 402 | + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); | |
| 403 | + | |
| 404 | + pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); | |
| 405 | + | |
| 406 | + atomic_dec(&qp->refcnt); | |
| 407 | + wait_event(qp->wait, !atomic_read(&qp->refcnt)); | |
| 408 | + | |
| 409 | + pvrdma_page_dir_cleanup(dev, &qp->pdir); | |
| 410 | + | |
| 411 | + kfree(qp); | |
| 412 | + | |
| 413 | + atomic_dec(&dev->num_qps); | |
| 414 | +} | |
| 415 | + | |
| 416 | +/** | |
| 417 | + * pvrdma_destroy_qp - destroy a queue pair | |
| 418 | + * @qp: the queue pair to destroy | |
| 419 | + * | |
| 420 | + * @return: 0 on success. | |
| 421 | + */ | |
| 422 | +int pvrdma_destroy_qp(struct ib_qp *qp) | |
| 423 | +{ | |
| 424 | + struct pvrdma_qp *vqp = to_vqp(qp); | |
| 425 | + union pvrdma_cmd_req req; | |
| 426 | + struct pvrdma_cmd_destroy_qp *cmd = &req.destroy_qp; | |
| 427 | + int ret; | |
| 428 | + | |
| 429 | + memset(cmd, 0, sizeof(*cmd)); | |
| 430 | + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_QP; | |
| 431 | + cmd->qp_handle = vqp->qp_handle; | |
| 432 | + | |
| 433 | + ret = pvrdma_cmd_post(to_vdev(qp->device), &req, NULL, 0); | |
| 434 | + if (ret < 0) | |
| 435 | + dev_warn(&to_vdev(qp->device)->pdev->dev, | |
| 436 | + "destroy queuepair failed, error: %d\n", ret); | |
| 437 | + | |
| 438 | + pvrdma_free_qp(vqp); | |
| 439 | + | |
| 440 | + return 0; | |
| 441 | +} | |
| 442 | + | |
| 443 | +/** | |
| 444 | + * pvrdma_modify_qp - modify queue pair attributes | |
| 445 | + * @ibqp: the queue pair | |
| 446 | + * @attr: the new queue pair's attributes | |
| 447 | + * @attr_mask: attributes mask | |
| 448 | + * @udata: user data | |
| 449 | + * | |
| 450 | + * @returns 0 on success, otherwise returns an errno. | |
| 451 | + */ | |
| 452 | +int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |
| 453 | + int attr_mask, struct ib_udata *udata) | |
| 454 | +{ | |
| 455 | + struct pvrdma_dev *dev = to_vdev(ibqp->device); | |
| 456 | + struct pvrdma_qp *qp = to_vqp(ibqp); | |
| 457 | + union pvrdma_cmd_req req; | |
| 458 | + union pvrdma_cmd_resp rsp; | |
| 459 | + struct pvrdma_cmd_modify_qp *cmd = &req.modify_qp; | |
| 460 | + int cur_state, next_state; | |
| 461 | + int ret; | |
| 462 | + | |
| 463 | + /* Sanity checking. Should need lock here */ | |
| 464 | + mutex_lock(&qp->mutex); | |
| 465 | + cur_state = (attr_mask & IB_QP_CUR_STATE) ? attr->cur_qp_state : | |
| 466 | + qp->state; | |
| 467 | + next_state = (attr_mask & IB_QP_STATE) ? attr->qp_state : cur_state; | |
| 468 | + | |
| 469 | + if (!ib_modify_qp_is_ok(cur_state, next_state, ibqp->qp_type, | |
| 470 | + attr_mask, IB_LINK_LAYER_ETHERNET)) { | |
| 471 | + ret = -EINVAL; | |
| 472 | + goto out; | |
| 473 | + } | |
| 474 | + | |
| 475 | + if (attr_mask & IB_QP_PORT) { | |
| 476 | + if (attr->port_num == 0 || | |
| 477 | + attr->port_num > ibqp->device->phys_port_cnt) { | |
| 478 | + ret = -EINVAL; | |
| 479 | + goto out; | |
| 480 | + } | |
| 481 | + } | |
| 482 | + | |
| 483 | + if (attr_mask & IB_QP_MIN_RNR_TIMER) { | |
| 484 | + if (attr->min_rnr_timer > 31) { | |
| 485 | + ret = -EINVAL; | |
| 486 | + goto out; | |
| 487 | + } | |
| 488 | + } | |
| 489 | + | |
| 490 | + if (attr_mask & IB_QP_PKEY_INDEX) { | |
| 491 | + if (attr->pkey_index >= dev->dsr->caps.max_pkeys) { | |
| 492 | + ret = -EINVAL; | |
| 493 | + goto out; | |
| 494 | + } | |
| 495 | + } | |
| 496 | + | |
| 497 | + if (attr_mask & IB_QP_QKEY) | |
| 498 | + qp->qkey = attr->qkey; | |
| 499 | + | |
| 500 | + if (cur_state == next_state && cur_state == IB_QPS_RESET) { | |
| 501 | + ret = 0; | |
| 502 | + goto out; | |
| 503 | + } | |
| 504 | + | |
| 505 | + qp->state = next_state; | |
| 506 | + memset(cmd, 0, sizeof(*cmd)); | |
| 507 | + cmd->hdr.cmd = PVRDMA_CMD_MODIFY_QP; | |
| 508 | + cmd->qp_handle = qp->qp_handle; | |
| 509 | + cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); | |
| 510 | + cmd->attrs.qp_state = ib_qp_state_to_pvrdma(attr->qp_state); | |
| 511 | + cmd->attrs.cur_qp_state = | |
| 512 | + ib_qp_state_to_pvrdma(attr->cur_qp_state); | |
| 513 | + cmd->attrs.path_mtu = ib_mtu_to_pvrdma(attr->path_mtu); | |
| 514 | + cmd->attrs.path_mig_state = | |
| 515 | + ib_mig_state_to_pvrdma(attr->path_mig_state); | |
| 516 | + cmd->attrs.qkey = attr->qkey; | |
| 517 | + cmd->attrs.rq_psn = attr->rq_psn; | |
| 518 | + cmd->attrs.sq_psn = attr->sq_psn; | |
| 519 | + cmd->attrs.dest_qp_num = attr->dest_qp_num; | |
| 520 | + cmd->attrs.qp_access_flags = | |
| 521 | + ib_access_flags_to_pvrdma(attr->qp_access_flags); | |
| 522 | + cmd->attrs.pkey_index = attr->pkey_index; | |
| 523 | + cmd->attrs.alt_pkey_index = attr->alt_pkey_index; | |
| 524 | + cmd->attrs.en_sqd_async_notify = attr->en_sqd_async_notify; | |
| 525 | + cmd->attrs.sq_draining = attr->sq_draining; | |
| 526 | + cmd->attrs.max_rd_atomic = attr->max_rd_atomic; | |
| 527 | + cmd->attrs.max_dest_rd_atomic = attr->max_dest_rd_atomic; | |
| 528 | + cmd->attrs.min_rnr_timer = attr->min_rnr_timer; | |
| 529 | + cmd->attrs.port_num = attr->port_num; | |
| 530 | + cmd->attrs.timeout = attr->timeout; | |
| 531 | + cmd->attrs.retry_cnt = attr->retry_cnt; | |
| 532 | + cmd->attrs.rnr_retry = attr->rnr_retry; | |
| 533 | + cmd->attrs.alt_port_num = attr->alt_port_num; | |
| 534 | + cmd->attrs.alt_timeout = attr->alt_timeout; | |
| 535 | + ib_qp_cap_to_pvrdma(&cmd->attrs.cap, &attr->cap); | |
| 536 | + ib_ah_attr_to_pvrdma(&cmd->attrs.ah_attr, &attr->ah_attr); | |
| 537 | + ib_ah_attr_to_pvrdma(&cmd->attrs.alt_ah_attr, &attr->alt_ah_attr); | |
| 538 | + | |
| 539 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_MODIFY_QP_RESP); | |
| 540 | + if (ret < 0) { | |
| 541 | + dev_warn(&dev->pdev->dev, | |
| 542 | + "could not modify queuepair, error: %d\n", ret); | |
| 543 | + } else if (rsp.hdr.err > 0) { | |
| 544 | + dev_warn(&dev->pdev->dev, | |
| 545 | + "cannot modify queuepair, error: %d\n", rsp.hdr.err); | |
| 546 | + ret = -EINVAL; | |
| 547 | + } | |
| 548 | + | |
| 549 | + if (ret == 0 && next_state == IB_QPS_RESET) | |
| 550 | + pvrdma_reset_qp(qp); | |
| 551 | + | |
| 552 | +out: | |
| 553 | + mutex_unlock(&qp->mutex); | |
| 554 | + | |
| 555 | + return ret; | |
| 556 | +} | |
| 557 | + | |
| 558 | +static inline void *get_sq_wqe(struct pvrdma_qp *qp, int n) | |
| 559 | +{ | |
| 560 | + return pvrdma_page_dir_get_ptr(&qp->pdir, | |
| 561 | + qp->sq.offset + n * qp->sq.wqe_size); | |
| 562 | +} | |
| 563 | + | |
| 564 | +static inline void *get_rq_wqe(struct pvrdma_qp *qp, int n) | |
| 565 | +{ | |
| 566 | + return pvrdma_page_dir_get_ptr(&qp->pdir, | |
| 567 | + qp->rq.offset + n * qp->rq.wqe_size); | |
| 568 | +} | |
| 569 | + | |
| 570 | +static int set_reg_seg(struct pvrdma_sq_wqe_hdr *wqe_hdr, struct ib_reg_wr *wr) | |
| 571 | +{ | |
| 572 | + struct pvrdma_user_mr *mr = to_vmr(wr->mr); | |
| 573 | + | |
| 574 | + wqe_hdr->wr.fast_reg.iova_start = mr->ibmr.iova; | |
| 575 | + wqe_hdr->wr.fast_reg.pl_pdir_dma = mr->pdir.dir_dma; | |
| 576 | + wqe_hdr->wr.fast_reg.page_shift = mr->page_shift; | |
| 577 | + wqe_hdr->wr.fast_reg.page_list_len = mr->npages; | |
| 578 | + wqe_hdr->wr.fast_reg.length = mr->ibmr.length; | |
| 579 | + wqe_hdr->wr.fast_reg.access_flags = wr->access; | |
| 580 | + wqe_hdr->wr.fast_reg.rkey = wr->key; | |
| 581 | + | |
| 582 | + return pvrdma_page_dir_insert_page_list(&mr->pdir, mr->pages, | |
| 583 | + mr->npages); | |
| 584 | +} | |
| 585 | + | |
| 586 | +/** | |
| 587 | + * pvrdma_post_send - post send work request entries on a QP | |
| 588 | + * @ibqp: the QP | |
| 589 | + * @wr: work request list to post | |
| 590 | + * @bad_wr: the first bad WR returned | |
| 591 | + * | |
| 592 | + * @return: 0 on success, otherwise errno returned. | |
| 593 | + */ | |
| 594 | +int pvrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |
| 595 | + struct ib_send_wr **bad_wr) | |
| 596 | +{ | |
| 597 | + struct pvrdma_qp *qp = to_vqp(ibqp); | |
| 598 | + struct pvrdma_dev *dev = to_vdev(ibqp->device); | |
| 599 | + unsigned long flags; | |
| 600 | + struct pvrdma_sq_wqe_hdr *wqe_hdr; | |
| 601 | + struct pvrdma_sge *sge; | |
| 602 | + int i, index; | |
| 603 | + int nreq; | |
| 604 | + int ret; | |
| 605 | + | |
| 606 | + /* | |
| 607 | + * In states lower than RTS, we can fail immediately. In other states, | |
| 608 | + * just post and let the device figure it out. | |
| 609 | + */ | |
| 610 | + if (qp->state < IB_QPS_RTS) { | |
| 611 | + *bad_wr = wr; | |
| 612 | + return -EINVAL; | |
| 613 | + } | |
| 614 | + | |
| 615 | + spin_lock_irqsave(&qp->sq.lock, flags); | |
| 616 | + | |
| 617 | + index = pvrdma_idx(&qp->sq.ring->prod_tail, qp->sq.wqe_cnt); | |
| 618 | + for (nreq = 0; wr; nreq++, wr = wr->next) { | |
| 619 | + unsigned int tail; | |
| 620 | + | |
| 621 | + if (unlikely(!pvrdma_idx_ring_has_space( | |
| 622 | + qp->sq.ring, qp->sq.wqe_cnt, &tail))) { | |
| 623 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 624 | + "send queue is full\n"); | |
| 625 | + *bad_wr = wr; | |
| 626 | + ret = -ENOMEM; | |
| 627 | + goto out; | |
| 628 | + } | |
| 629 | + | |
| 630 | + if (unlikely(wr->num_sge > qp->sq.max_sg || wr->num_sge < 0)) { | |
| 631 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 632 | + "send SGE overflow\n"); | |
| 633 | + *bad_wr = wr; | |
| 634 | + ret = -EINVAL; | |
| 635 | + goto out; | |
| 636 | + } | |
| 637 | + | |
| 638 | + if (unlikely(wr->opcode < 0)) { | |
| 639 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 640 | + "invalid send opcode\n"); | |
| 641 | + *bad_wr = wr; | |
| 642 | + ret = -EINVAL; | |
| 643 | + goto out; | |
| 644 | + } | |
| 645 | + | |
| 646 | + /* | |
| 647 | + * Only support UD, RC. | |
| 648 | + * Need to check opcode table for thorough checking. | |
| 649 | + * opcode _UD _UC _RC | |
| 650 | + * _SEND x x x | |
| 651 | + * _SEND_WITH_IMM x x x | |
| 652 | + * _RDMA_WRITE x x | |
| 653 | + * _RDMA_WRITE_WITH_IMM x x | |
| 654 | + * _LOCAL_INV x x | |
| 655 | + * _SEND_WITH_INV x x | |
| 656 | + * _RDMA_READ x | |
| 657 | + * _ATOMIC_CMP_AND_SWP x | |
| 658 | + * _ATOMIC_FETCH_AND_ADD x | |
| 659 | + * _MASK_ATOMIC_CMP_AND_SWP x | |
| 660 | + * _MASK_ATOMIC_FETCH_AND_ADD x | |
| 661 | + * _REG_MR x | |
| 662 | + * | |
| 663 | + */ | |
| 664 | + if (qp->ibqp.qp_type != IB_QPT_UD && | |
| 665 | + qp->ibqp.qp_type != IB_QPT_RC && | |
| 666 | + wr->opcode != IB_WR_SEND) { | |
| 667 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 668 | + "unsupported queuepair type\n"); | |
| 669 | + *bad_wr = wr; | |
| 670 | + ret = -EINVAL; | |
| 671 | + goto out; | |
| 672 | + } else if (qp->ibqp.qp_type == IB_QPT_UD || | |
| 673 | + qp->ibqp.qp_type == IB_QPT_GSI) { | |
| 674 | + if (wr->opcode != IB_WR_SEND && | |
| 675 | + wr->opcode != IB_WR_SEND_WITH_IMM) { | |
| 676 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 677 | + "invalid send opcode\n"); | |
| 678 | + *bad_wr = wr; | |
| 679 | + ret = -EINVAL; | |
| 680 | + goto out; | |
| 681 | + } | |
| 682 | + } | |
| 683 | + | |
| 684 | + wqe_hdr = (struct pvrdma_sq_wqe_hdr *)get_sq_wqe(qp, index); | |
| 685 | + memset(wqe_hdr, 0, sizeof(*wqe_hdr)); | |
| 686 | + wqe_hdr->wr_id = wr->wr_id; | |
| 687 | + wqe_hdr->num_sge = wr->num_sge; | |
| 688 | + wqe_hdr->opcode = ib_wr_opcode_to_pvrdma(wr->opcode); | |
| 689 | + wqe_hdr->send_flags = ib_send_flags_to_pvrdma(wr->send_flags); | |
| 690 | + if (wr->opcode == IB_WR_SEND_WITH_IMM || | |
| 691 | + wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) | |
| 692 | + wqe_hdr->ex.imm_data = wr->ex.imm_data; | |
| 693 | + | |
| 694 | + switch (qp->ibqp.qp_type) { | |
| 695 | + case IB_QPT_GSI: | |
| 696 | + case IB_QPT_UD: | |
| 697 | + if (unlikely(!ud_wr(wr)->ah)) { | |
| 698 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 699 | + "invalid address handle\n"); | |
| 700 | + *bad_wr = wr; | |
| 701 | + ret = -EINVAL; | |
| 702 | + goto out; | |
| 703 | + } | |
| 704 | + | |
| 705 | + /* | |
| 706 | + * Use qkey from qp context if high order bit set, | |
| 707 | + * otherwise from work request. | |
| 708 | + */ | |
| 709 | + wqe_hdr->wr.ud.remote_qpn = ud_wr(wr)->remote_qpn; | |
| 710 | + wqe_hdr->wr.ud.remote_qkey = | |
| 711 | + ud_wr(wr)->remote_qkey & 0x80000000 ? | |
| 712 | + qp->qkey : ud_wr(wr)->remote_qkey; | |
| 713 | + wqe_hdr->wr.ud.av = to_vah(ud_wr(wr)->ah)->av; | |
| 714 | + | |
| 715 | + break; | |
| 716 | + case IB_QPT_RC: | |
| 717 | + switch (wr->opcode) { | |
| 718 | + case IB_WR_RDMA_READ: | |
| 719 | + case IB_WR_RDMA_WRITE: | |
| 720 | + case IB_WR_RDMA_WRITE_WITH_IMM: | |
| 721 | + wqe_hdr->wr.rdma.remote_addr = | |
| 722 | + rdma_wr(wr)->remote_addr; | |
| 723 | + wqe_hdr->wr.rdma.rkey = rdma_wr(wr)->rkey; | |
| 724 | + break; | |
| 725 | + case IB_WR_LOCAL_INV: | |
| 726 | + case IB_WR_SEND_WITH_INV: | |
| 727 | + wqe_hdr->ex.invalidate_rkey = | |
| 728 | + wr->ex.invalidate_rkey; | |
| 729 | + break; | |
| 730 | + case IB_WR_ATOMIC_CMP_AND_SWP: | |
| 731 | + case IB_WR_ATOMIC_FETCH_AND_ADD: | |
| 732 | + wqe_hdr->wr.atomic.remote_addr = | |
| 733 | + atomic_wr(wr)->remote_addr; | |
| 734 | + wqe_hdr->wr.atomic.rkey = atomic_wr(wr)->rkey; | |
| 735 | + wqe_hdr->wr.atomic.compare_add = | |
| 736 | + atomic_wr(wr)->compare_add; | |
| 737 | + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) | |
| 738 | + wqe_hdr->wr.atomic.swap = | |
| 739 | + atomic_wr(wr)->swap; | |
| 740 | + break; | |
| 741 | + case IB_WR_REG_MR: | |
| 742 | + ret = set_reg_seg(wqe_hdr, reg_wr(wr)); | |
| 743 | + if (ret < 0) { | |
| 744 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 745 | + "Failed to set fast register work request\n"); | |
| 746 | + *bad_wr = wr; | |
| 747 | + goto out; | |
| 748 | + } | |
| 749 | + break; | |
| 750 | + default: | |
| 751 | + break; | |
| 752 | + } | |
| 753 | + | |
| 754 | + break; | |
| 755 | + default: | |
| 756 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 757 | + "invalid queuepair type\n"); | |
| 758 | + ret = -EINVAL; | |
| 759 | + *bad_wr = wr; | |
| 760 | + goto out; | |
| 761 | + } | |
| 762 | + | |
| 763 | + sge = (struct pvrdma_sge *)(wqe_hdr + 1); | |
| 764 | + for (i = 0; i < wr->num_sge; i++) { | |
| 765 | + /* Need to check wqe_size 0 or max size */ | |
| 766 | + sge->addr = wr->sg_list[i].addr; | |
| 767 | + sge->length = wr->sg_list[i].length; | |
| 768 | + sge->lkey = wr->sg_list[i].lkey; | |
| 769 | + sge++; | |
| 770 | + } | |
| 771 | + | |
| 772 | + /* Make sure wqe is written before index update */ | |
| 773 | + smp_wmb(); | |
| 774 | + | |
| 775 | + index++; | |
| 776 | + if (unlikely(index >= qp->sq.wqe_cnt)) | |
| 777 | + index = 0; | |
| 778 | + /* Update shared sq ring */ | |
| 779 | + pvrdma_idx_ring_inc(&qp->sq.ring->prod_tail, | |
| 780 | + qp->sq.wqe_cnt); | |
| 781 | + } | |
| 782 | + | |
| 783 | + ret = 0; | |
| 784 | + | |
| 785 | +out: | |
| 786 | + spin_unlock_irqrestore(&qp->sq.lock, flags); | |
| 787 | + | |
| 788 | + if (!ret) | |
| 789 | + pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_SEND | qp->qp_handle); | |
| 790 | + | |
| 791 | + return ret; | |
| 792 | +} | |
| 793 | + | |
| 794 | +/** | |
| 795 | + * pvrdma_post_receive - post receive work request entries on a QP | |
| 796 | + * @ibqp: the QP | |
| 797 | + * @wr: the work request list to post | |
| 798 | + * @bad_wr: the first bad WR returned | |
| 799 | + * | |
| 800 | + * @return: 0 on success, otherwise errno returned. | |
| 801 | + */ | |
| 802 | +int pvrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |
| 803 | + struct ib_recv_wr **bad_wr) | |
| 804 | +{ | |
| 805 | + struct pvrdma_dev *dev = to_vdev(ibqp->device); | |
| 806 | + unsigned long flags; | |
| 807 | + struct pvrdma_qp *qp = to_vqp(ibqp); | |
| 808 | + struct pvrdma_rq_wqe_hdr *wqe_hdr; | |
| 809 | + struct pvrdma_sge *sge; | |
| 810 | + int index, nreq; | |
| 811 | + int ret = 0; | |
| 812 | + int i; | |
| 813 | + | |
| 814 | + /* | |
| 815 | + * In the RESET state, we can fail immediately. For other states, | |
| 816 | + * just post and let the device figure it out. | |
| 817 | + */ | |
| 818 | + if (qp->state == IB_QPS_RESET) { | |
| 819 | + *bad_wr = wr; | |
| 820 | + return -EINVAL; | |
| 821 | + } | |
| 822 | + | |
| 823 | + spin_lock_irqsave(&qp->rq.lock, flags); | |
| 824 | + | |
| 825 | + index = pvrdma_idx(&qp->rq.ring->prod_tail, qp->rq.wqe_cnt); | |
| 826 | + for (nreq = 0; wr; nreq++, wr = wr->next) { | |
| 827 | + unsigned int tail; | |
| 828 | + | |
| 829 | + if (unlikely(wr->num_sge > qp->rq.max_sg || | |
| 830 | + wr->num_sge < 0)) { | |
| 831 | + ret = -EINVAL; | |
| 832 | + *bad_wr = wr; | |
| 833 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 834 | + "recv SGE overflow\n"); | |
| 835 | + goto out; | |
| 836 | + } | |
| 837 | + | |
| 838 | + if (unlikely(!pvrdma_idx_ring_has_space( | |
| 839 | + qp->rq.ring, qp->rq.wqe_cnt, &tail))) { | |
| 840 | + ret = -ENOMEM; | |
| 841 | + *bad_wr = wr; | |
| 842 | + dev_warn_ratelimited(&dev->pdev->dev, | |
| 843 | + "recv queue full\n"); | |
| 844 | + goto out; | |
| 845 | + } | |
| 846 | + | |
| 847 | + wqe_hdr = (struct pvrdma_rq_wqe_hdr *)get_rq_wqe(qp, index); | |
| 848 | + wqe_hdr->wr_id = wr->wr_id; | |
| 849 | + wqe_hdr->num_sge = wr->num_sge; | |
| 850 | + wqe_hdr->total_len = 0; | |
| 851 | + | |
| 852 | + sge = (struct pvrdma_sge *)(wqe_hdr + 1); | |
| 853 | + for (i = 0; i < wr->num_sge; i++) { | |
| 854 | + sge->addr = wr->sg_list[i].addr; | |
| 855 | + sge->length = wr->sg_list[i].length; | |
| 856 | + sge->lkey = wr->sg_list[i].lkey; | |
| 857 | + sge++; | |
| 858 | + } | |
| 859 | + | |
| 860 | + /* Make sure wqe is written before index update */ | |
| 861 | + smp_wmb(); | |
| 862 | + | |
| 863 | + index++; | |
| 864 | + if (unlikely(index >= qp->rq.wqe_cnt)) | |
| 865 | + index = 0; | |
| 866 | + /* Update shared rq ring */ | |
| 867 | + pvrdma_idx_ring_inc(&qp->rq.ring->prod_tail, | |
| 868 | + qp->rq.wqe_cnt); | |
| 869 | + } | |
| 870 | + | |
| 871 | + spin_unlock_irqrestore(&qp->rq.lock, flags); | |
| 872 | + | |
| 873 | + pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_RECV | qp->qp_handle); | |
| 874 | + | |
| 875 | + return ret; | |
| 876 | + | |
| 877 | +out: | |
| 878 | + spin_unlock_irqrestore(&qp->rq.lock, flags); | |
| 879 | + | |
| 880 | + return ret; | |
| 881 | +} | |
| 882 | + | |
| 883 | +/** | |
| 884 | + * pvrdma_query_qp - query a queue pair's attributes | |
| 885 | + * @ibqp: the queue pair to query | |
| 886 | + * @attr: the queue pair's attributes | |
| 887 | + * @attr_mask: attributes mask | |
| 888 | + * @init_attr: initial queue pair attributes | |
| 889 | + * | |
| 890 | + * @returns 0 on success, otherwise returns an errno. | |
| 891 | + */ | |
| 892 | +int pvrdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |
| 893 | + int attr_mask, struct ib_qp_init_attr *init_attr) | |
| 894 | +{ | |
| 895 | + struct pvrdma_dev *dev = to_vdev(ibqp->device); | |
| 896 | + struct pvrdma_qp *qp = to_vqp(ibqp); | |
| 897 | + union pvrdma_cmd_req req; | |
| 898 | + union pvrdma_cmd_resp rsp; | |
| 899 | + struct pvrdma_cmd_query_qp *cmd = &req.query_qp; | |
| 900 | + struct pvrdma_cmd_query_qp_resp *resp = &rsp.query_qp_resp; | |
| 901 | + int ret = 0; | |
| 902 | + | |
| 903 | + mutex_lock(&qp->mutex); | |
| 904 | + | |
| 905 | + if (qp->state == IB_QPS_RESET) { | |
| 906 | + attr->qp_state = IB_QPS_RESET; | |
| 907 | + goto out; | |
| 908 | + } | |
| 909 | + | |
| 910 | + memset(cmd, 0, sizeof(*cmd)); | |
| 911 | + cmd->hdr.cmd = PVRDMA_CMD_QUERY_QP; | |
| 912 | + cmd->qp_handle = qp->qp_handle; | |
| 913 | + cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); | |
| 914 | + | |
| 915 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_QP_RESP); | |
| 916 | + if (ret < 0) { | |
| 917 | + dev_warn(&dev->pdev->dev, | |
| 918 | + "could not query queuepair, error: %d\n", ret); | |
| 919 | + goto out; | |
| 920 | + } | |
| 921 | + | |
| 922 | + attr->qp_state = pvrdma_qp_state_to_ib(resp->attrs.qp_state); | |
| 923 | + attr->cur_qp_state = | |
| 924 | + pvrdma_qp_state_to_ib(resp->attrs.cur_qp_state); | |
| 925 | + attr->path_mtu = pvrdma_mtu_to_ib(resp->attrs.path_mtu); | |
| 926 | + attr->path_mig_state = | |
| 927 | + pvrdma_mig_state_to_ib(resp->attrs.path_mig_state); | |
| 928 | + attr->qkey = resp->attrs.qkey; | |
| 929 | + attr->rq_psn = resp->attrs.rq_psn; | |
| 930 | + attr->sq_psn = resp->attrs.sq_psn; | |
| 931 | + attr->dest_qp_num = resp->attrs.dest_qp_num; | |
| 932 | + attr->qp_access_flags = | |
| 933 | + pvrdma_access_flags_to_ib(resp->attrs.qp_access_flags); | |
| 934 | + attr->pkey_index = resp->attrs.pkey_index; | |
| 935 | + attr->alt_pkey_index = resp->attrs.alt_pkey_index; | |
| 936 | + attr->en_sqd_async_notify = resp->attrs.en_sqd_async_notify; | |
| 937 | + attr->sq_draining = resp->attrs.sq_draining; | |
| 938 | + attr->max_rd_atomic = resp->attrs.max_rd_atomic; | |
| 939 | + attr->max_dest_rd_atomic = resp->attrs.max_dest_rd_atomic; | |
| 940 | + attr->min_rnr_timer = resp->attrs.min_rnr_timer; | |
| 941 | + attr->port_num = resp->attrs.port_num; | |
| 942 | + attr->timeout = resp->attrs.timeout; | |
| 943 | + attr->retry_cnt = resp->attrs.retry_cnt; | |
| 944 | + attr->rnr_retry = resp->attrs.rnr_retry; | |
| 945 | + attr->alt_port_num = resp->attrs.alt_port_num; | |
| 946 | + attr->alt_timeout = resp->attrs.alt_timeout; | |
| 947 | + pvrdma_qp_cap_to_ib(&attr->cap, &resp->attrs.cap); | |
| 948 | + pvrdma_ah_attr_to_ib(&attr->ah_attr, &resp->attrs.ah_attr); | |
| 949 | + pvrdma_ah_attr_to_ib(&attr->alt_ah_attr, &resp->attrs.alt_ah_attr); | |
| 950 | + | |
| 951 | + qp->state = attr->qp_state; | |
| 952 | + | |
| 953 | + ret = 0; | |
| 954 | + | |
| 955 | +out: | |
| 956 | + attr->cur_qp_state = attr->qp_state; | |
| 957 | + | |
| 958 | + init_attr->event_handler = qp->ibqp.event_handler; | |
| 959 | + init_attr->qp_context = qp->ibqp.qp_context; | |
| 960 | + init_attr->send_cq = qp->ibqp.send_cq; | |
| 961 | + init_attr->recv_cq = qp->ibqp.recv_cq; | |
| 962 | + init_attr->srq = qp->ibqp.srq; | |
| 963 | + init_attr->xrcd = NULL; | |
| 964 | + init_attr->cap = attr->cap; | |
| 965 | + init_attr->sq_sig_type = 0; | |
| 966 | + init_attr->qp_type = qp->ibqp.qp_type; | |
| 967 | + init_attr->create_flags = 0; | |
| 968 | + init_attr->port_num = qp->port; | |
| 969 | + | |
| 970 | + mutex_unlock(&qp->mutex); | |
| 971 | + return ret; | |
| 972 | +} | |
| @@ -0,0 +1,131 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#ifndef __PVRDMA_RING_H__ | |
| 47 | +#define __PVRDMA_RING_H__ | |
| 48 | + | |
| 49 | +#include <linux/types.h> | |
| 50 | + | |
| 51 | +#define PVRDMA_INVALID_IDX -1 /* Invalid index. */ | |
| 52 | + | |
| 53 | +struct pvrdma_ring { | |
| 54 | + atomic_t prod_tail; /* Producer tail. */ | |
| 55 | + atomic_t cons_head; /* Consumer head. */ | |
| 56 | +}; | |
| 57 | + | |
| 58 | +struct pvrdma_ring_state { | |
| 59 | + struct pvrdma_ring tx; /* Tx ring. */ | |
| 60 | + struct pvrdma_ring rx; /* Rx ring. */ | |
| 61 | +}; | |
| 62 | + | |
| 63 | +static inline int pvrdma_idx_valid(__u32 idx, __u32 max_elems) | |
| 64 | +{ | |
| 65 | + /* Generates fewer instructions than a less-than. */ | |
| 66 | + return (idx & ~((max_elems << 1) - 1)) == 0; | |
| 67 | +} | |
| 68 | + | |
| 69 | +static inline __s32 pvrdma_idx(atomic_t *var, __u32 max_elems) | |
| 70 | +{ | |
| 71 | + const unsigned int idx = atomic_read(var); | |
| 72 | + | |
| 73 | + if (pvrdma_idx_valid(idx, max_elems)) | |
| 74 | + return idx & (max_elems - 1); | |
| 75 | + return PVRDMA_INVALID_IDX; | |
| 76 | +} | |
| 77 | + | |
| 78 | +static inline void pvrdma_idx_ring_inc(atomic_t *var, __u32 max_elems) | |
| 79 | +{ | |
| 80 | + __u32 idx = atomic_read(var) + 1; /* Increment. */ | |
| 81 | + | |
| 82 | + idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ | |
| 83 | + atomic_set(var, idx); | |
| 84 | +} | |
| 85 | + | |
| 86 | +static inline __s32 pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, | |
| 87 | + __u32 max_elems, __u32 *out_tail) | |
| 88 | +{ | |
| 89 | + const __u32 tail = atomic_read(&r->prod_tail); | |
| 90 | + const __u32 head = atomic_read(&r->cons_head); | |
| 91 | + | |
| 92 | + if (pvrdma_idx_valid(tail, max_elems) && | |
| 93 | + pvrdma_idx_valid(head, max_elems)) { | |
| 94 | + *out_tail = tail & (max_elems - 1); | |
| 95 | + return tail != (head ^ max_elems); | |
| 96 | + } | |
| 97 | + return PVRDMA_INVALID_IDX; | |
| 98 | +} | |
| 99 | + | |
| 100 | +static inline __s32 pvrdma_idx_ring_has_data(const struct pvrdma_ring *r, | |
| 101 | + __u32 max_elems, __u32 *out_head) | |
| 102 | +{ | |
| 103 | + const __u32 tail = atomic_read(&r->prod_tail); | |
| 104 | + const __u32 head = atomic_read(&r->cons_head); | |
| 105 | + | |
| 106 | + if (pvrdma_idx_valid(tail, max_elems) && | |
| 107 | + pvrdma_idx_valid(head, max_elems)) { | |
| 108 | + *out_head = head & (max_elems - 1); | |
| 109 | + return tail != head; | |
| 110 | + } | |
| 111 | + return PVRDMA_INVALID_IDX; | |
| 112 | +} | |
| 113 | + | |
| 114 | +static inline bool pvrdma_idx_ring_is_valid_idx(const struct pvrdma_ring *r, | |
| 115 | + __u32 max_elems, __u32 *idx) | |
| 116 | +{ | |
| 117 | + const __u32 tail = atomic_read(&r->prod_tail); | |
| 118 | + const __u32 head = atomic_read(&r->cons_head); | |
| 119 | + | |
| 120 | + if (pvrdma_idx_valid(tail, max_elems) && | |
| 121 | + pvrdma_idx_valid(head, max_elems) && | |
| 122 | + pvrdma_idx_valid(*idx, max_elems)) { | |
| 123 | + if (tail > head && (*idx < tail && *idx >= head)) | |
| 124 | + return true; | |
| 125 | + else if (head > tail && (*idx >= head || *idx < tail)) | |
| 126 | + return true; | |
| 127 | + } | |
| 128 | + return false; | |
| 129 | +} | |
| 130 | + | |
| 131 | +#endif /* __PVRDMA_RING_H__ */ | |
| @@ -0,0 +1,579 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#include <asm/page.h> | |
| 47 | +#include <linux/inet.h> | |
| 48 | +#include <linux/io.h> | |
| 49 | +#include <rdma/ib_addr.h> | |
| 50 | +#include <rdma/ib_smi.h> | |
| 51 | +#include <rdma/ib_user_verbs.h> | |
| 52 | +#include <rdma/vmw_pvrdma-abi.h> | |
| 53 | + | |
| 54 | +#include "pvrdma.h" | |
| 55 | + | |
| 56 | +/** | |
| 57 | + * pvrdma_query_device - query device | |
| 58 | + * @ibdev: the device to query | |
| 59 | + * @props: the device properties | |
| 60 | + * @uhw: user data | |
| 61 | + * | |
| 62 | + * @return: 0 on success, otherwise negative errno | |
| 63 | + */ | |
| 64 | +int pvrdma_query_device(struct ib_device *ibdev, | |
| 65 | + struct ib_device_attr *props, | |
| 66 | + struct ib_udata *uhw) | |
| 67 | +{ | |
| 68 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 69 | + | |
| 70 | + if (uhw->inlen || uhw->outlen) | |
| 71 | + return -EINVAL; | |
| 72 | + | |
| 73 | + memset(props, 0, sizeof(*props)); | |
| 74 | + | |
| 75 | + props->fw_ver = dev->dsr->caps.fw_ver; | |
| 76 | + props->sys_image_guid = dev->dsr->caps.sys_image_guid; | |
| 77 | + props->max_mr_size = dev->dsr->caps.max_mr_size; | |
| 78 | + props->page_size_cap = dev->dsr->caps.page_size_cap; | |
| 79 | + props->vendor_id = dev->dsr->caps.vendor_id; | |
| 80 | + props->vendor_part_id = dev->pdev->device; | |
| 81 | + props->hw_ver = dev->dsr->caps.hw_ver; | |
| 82 | + props->max_qp = dev->dsr->caps.max_qp; | |
| 83 | + props->max_qp_wr = dev->dsr->caps.max_qp_wr; | |
| 84 | + props->device_cap_flags = dev->dsr->caps.device_cap_flags; | |
| 85 | + props->max_sge = dev->dsr->caps.max_sge; | |
| 86 | + props->max_cq = dev->dsr->caps.max_cq; | |
| 87 | + props->max_cqe = dev->dsr->caps.max_cqe; | |
| 88 | + props->max_mr = dev->dsr->caps.max_mr; | |
| 89 | + props->max_pd = dev->dsr->caps.max_pd; | |
| 90 | + props->max_qp_rd_atom = dev->dsr->caps.max_qp_rd_atom; | |
| 91 | + props->max_qp_init_rd_atom = dev->dsr->caps.max_qp_init_rd_atom; | |
| 92 | + props->atomic_cap = | |
| 93 | + dev->dsr->caps.atomic_ops & | |
| 94 | + (PVRDMA_ATOMIC_OP_COMP_SWAP | PVRDMA_ATOMIC_OP_FETCH_ADD) ? | |
| 95 | + IB_ATOMIC_HCA : IB_ATOMIC_NONE; | |
| 96 | + props->masked_atomic_cap = props->atomic_cap; | |
| 97 | + props->max_ah = dev->dsr->caps.max_ah; | |
| 98 | + props->max_pkeys = dev->dsr->caps.max_pkeys; | |
| 99 | + props->local_ca_ack_delay = dev->dsr->caps.local_ca_ack_delay; | |
| 100 | + if ((dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_LOCAL_INV) && | |
| 101 | + (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_REMOTE_INV) && | |
| 102 | + (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_FAST_REG_WR)) { | |
| 103 | + props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; | |
| 104 | + } | |
| 105 | + | |
| 106 | + return 0; | |
| 107 | +} | |
| 108 | + | |
| 109 | +/** | |
| 110 | + * pvrdma_query_port - query device port attributes | |
| 111 | + * @ibdev: the device to query | |
| 112 | + * @port: the port number | |
| 113 | + * @props: the device properties | |
| 114 | + * | |
| 115 | + * @return: 0 on success, otherwise negative errno | |
| 116 | + */ | |
| 117 | +int pvrdma_query_port(struct ib_device *ibdev, u8 port, | |
| 118 | + struct ib_port_attr *props) | |
| 119 | +{ | |
| 120 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 121 | + union pvrdma_cmd_req req; | |
| 122 | + union pvrdma_cmd_resp rsp; | |
| 123 | + struct pvrdma_cmd_query_port *cmd = &req.query_port; | |
| 124 | + struct pvrdma_cmd_query_port_resp *resp = &rsp.query_port_resp; | |
| 125 | + int err; | |
| 126 | + | |
| 127 | + memset(cmd, 0, sizeof(*cmd)); | |
| 128 | + cmd->hdr.cmd = PVRDMA_CMD_QUERY_PORT; | |
| 129 | + cmd->port_num = port; | |
| 130 | + | |
| 131 | + err = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_PORT_RESP); | |
| 132 | + if (err < 0) { | |
| 133 | + dev_warn(&dev->pdev->dev, | |
| 134 | + "could not query port, error: %d\n", err); | |
| 135 | + return err; | |
| 136 | + } | |
| 137 | + | |
| 138 | + memset(props, 0, sizeof(*props)); | |
| 139 | + | |
| 140 | + props->state = pvrdma_port_state_to_ib(resp->attrs.state); | |
| 141 | + props->max_mtu = pvrdma_mtu_to_ib(resp->attrs.max_mtu); | |
| 142 | + props->active_mtu = pvrdma_mtu_to_ib(resp->attrs.active_mtu); | |
| 143 | + props->gid_tbl_len = resp->attrs.gid_tbl_len; | |
| 144 | + props->port_cap_flags = | |
| 145 | + pvrdma_port_cap_flags_to_ib(resp->attrs.port_cap_flags); | |
| 146 | + props->max_msg_sz = resp->attrs.max_msg_sz; | |
| 147 | + props->bad_pkey_cntr = resp->attrs.bad_pkey_cntr; | |
| 148 | + props->qkey_viol_cntr = resp->attrs.qkey_viol_cntr; | |
| 149 | + props->pkey_tbl_len = resp->attrs.pkey_tbl_len; | |
| 150 | + props->lid = resp->attrs.lid; | |
| 151 | + props->sm_lid = resp->attrs.sm_lid; | |
| 152 | + props->lmc = resp->attrs.lmc; | |
| 153 | + props->max_vl_num = resp->attrs.max_vl_num; | |
| 154 | + props->sm_sl = resp->attrs.sm_sl; | |
| 155 | + props->subnet_timeout = resp->attrs.subnet_timeout; | |
| 156 | + props->init_type_reply = resp->attrs.init_type_reply; | |
| 157 | + props->active_width = pvrdma_port_width_to_ib(resp->attrs.active_width); | |
| 158 | + props->active_speed = pvrdma_port_speed_to_ib(resp->attrs.active_speed); | |
| 159 | + props->phys_state = resp->attrs.phys_state; | |
| 160 | + | |
| 161 | + return 0; | |
| 162 | +} | |
| 163 | + | |
| 164 | +/** | |
| 165 | + * pvrdma_query_gid - query device gid | |
| 166 | + * @ibdev: the device to query | |
| 167 | + * @port: the port number | |
| 168 | + * @index: the index | |
| 169 | + * @gid: the device gid value | |
| 170 | + * | |
| 171 | + * @return: 0 on success, otherwise negative errno | |
| 172 | + */ | |
| 173 | +int pvrdma_query_gid(struct ib_device *ibdev, u8 port, int index, | |
| 174 | + union ib_gid *gid) | |
| 175 | +{ | |
| 176 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 177 | + | |
| 178 | + if (index >= dev->dsr->caps.gid_tbl_len) | |
| 179 | + return -EINVAL; | |
| 180 | + | |
| 181 | + memcpy(gid, &dev->sgid_tbl[index], sizeof(union ib_gid)); | |
| 182 | + | |
| 183 | + return 0; | |
| 184 | +} | |
| 185 | + | |
| 186 | +/** | |
| 187 | + * pvrdma_query_pkey - query device port's P_Key table | |
| 188 | + * @ibdev: the device to query | |
| 189 | + * @port: the port number | |
| 190 | + * @index: the index | |
| 191 | + * @pkey: the device P_Key value | |
| 192 | + * | |
| 193 | + * @return: 0 on success, otherwise negative errno | |
| 194 | + */ | |
| 195 | +int pvrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, | |
| 196 | + u16 *pkey) | |
| 197 | +{ | |
| 198 | + int err = 0; | |
| 199 | + union pvrdma_cmd_req req; | |
| 200 | + union pvrdma_cmd_resp rsp; | |
| 201 | + struct pvrdma_cmd_query_pkey *cmd = &req.query_pkey; | |
| 202 | + | |
| 203 | + memset(cmd, 0, sizeof(*cmd)); | |
| 204 | + cmd->hdr.cmd = PVRDMA_CMD_QUERY_PKEY; | |
| 205 | + cmd->port_num = port; | |
| 206 | + cmd->index = index; | |
| 207 | + | |
| 208 | + err = pvrdma_cmd_post(to_vdev(ibdev), &req, &rsp, | |
| 209 | + PVRDMA_CMD_QUERY_PKEY_RESP); | |
| 210 | + if (err < 0) { | |
| 211 | + dev_warn(&to_vdev(ibdev)->pdev->dev, | |
| 212 | + "could not query pkey, error: %d\n", err); | |
| 213 | + return err; | |
| 214 | + } | |
| 215 | + | |
| 216 | + *pkey = rsp.query_pkey_resp.pkey; | |
| 217 | + | |
| 218 | + return 0; | |
| 219 | +} | |
| 220 | + | |
| 221 | +enum rdma_link_layer pvrdma_port_link_layer(struct ib_device *ibdev, | |
| 222 | + u8 port) | |
| 223 | +{ | |
| 224 | + return IB_LINK_LAYER_ETHERNET; | |
| 225 | +} | |
| 226 | + | |
| 227 | +int pvrdma_modify_device(struct ib_device *ibdev, int mask, | |
| 228 | + struct ib_device_modify *props) | |
| 229 | +{ | |
| 230 | + unsigned long flags; | |
| 231 | + | |
| 232 | + if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | | |
| 233 | + IB_DEVICE_MODIFY_NODE_DESC)) { | |
| 234 | + dev_warn(&to_vdev(ibdev)->pdev->dev, | |
| 235 | + "unsupported device modify mask %#x\n", mask); | |
| 236 | + return -EOPNOTSUPP; | |
| 237 | + } | |
| 238 | + | |
| 239 | + if (mask & IB_DEVICE_MODIFY_NODE_DESC) { | |
| 240 | + spin_lock_irqsave(&to_vdev(ibdev)->desc_lock, flags); | |
| 241 | + memcpy(ibdev->node_desc, props->node_desc, 64); | |
| 242 | + spin_unlock_irqrestore(&to_vdev(ibdev)->desc_lock, flags); | |
| 243 | + } | |
| 244 | + | |
| 245 | + if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) { | |
| 246 | + mutex_lock(&to_vdev(ibdev)->port_mutex); | |
| 247 | + to_vdev(ibdev)->sys_image_guid = | |
| 248 | + cpu_to_be64(props->sys_image_guid); | |
| 249 | + mutex_unlock(&to_vdev(ibdev)->port_mutex); | |
| 250 | + } | |
| 251 | + | |
| 252 | + return 0; | |
| 253 | +} | |
| 254 | + | |
| 255 | +/** | |
| 256 | + * pvrdma_modify_port - modify device port attributes | |
| 257 | + * @ibdev: the device to modify | |
| 258 | + * @port: the port number | |
| 259 | + * @mask: attributes to modify | |
| 260 | + * @props: the device properties | |
| 261 | + * | |
| 262 | + * @return: 0 on success, otherwise negative errno | |
| 263 | + */ | |
| 264 | +int pvrdma_modify_port(struct ib_device *ibdev, u8 port, int mask, | |
| 265 | + struct ib_port_modify *props) | |
| 266 | +{ | |
| 267 | + struct ib_port_attr attr; | |
| 268 | + struct pvrdma_dev *vdev = to_vdev(ibdev); | |
| 269 | + int ret; | |
| 270 | + | |
| 271 | + if (mask & ~IB_PORT_SHUTDOWN) { | |
| 272 | + dev_warn(&vdev->pdev->dev, | |
| 273 | + "unsupported port modify mask %#x\n", mask); | |
| 274 | + return -EOPNOTSUPP; | |
| 275 | + } | |
| 276 | + | |
| 277 | + mutex_lock(&vdev->port_mutex); | |
| 278 | + ret = pvrdma_query_port(ibdev, port, &attr); | |
| 279 | + if (ret) | |
| 280 | + goto out; | |
| 281 | + | |
| 282 | + vdev->port_cap_mask |= props->set_port_cap_mask; | |
| 283 | + vdev->port_cap_mask &= ~props->clr_port_cap_mask; | |
| 284 | + | |
| 285 | + if (mask & IB_PORT_SHUTDOWN) | |
| 286 | + vdev->ib_active = false; | |
| 287 | + | |
| 288 | +out: | |
| 289 | + mutex_unlock(&vdev->port_mutex); | |
| 290 | + return ret; | |
| 291 | +} | |
| 292 | + | |
| 293 | +/** | |
| 294 | + * pvrdma_alloc_ucontext - allocate ucontext | |
| 295 | + * @ibdev: the IB device | |
| 296 | + * @udata: user data | |
| 297 | + * | |
| 298 | + * @return: the ib_ucontext pointer on success, otherwise errno. | |
| 299 | + */ | |
| 300 | +struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, | |
| 301 | + struct ib_udata *udata) | |
| 302 | +{ | |
| 303 | + struct pvrdma_dev *vdev = to_vdev(ibdev); | |
| 304 | + struct pvrdma_ucontext *context; | |
| 305 | + union pvrdma_cmd_req req; | |
| 306 | + union pvrdma_cmd_resp rsp; | |
| 307 | + struct pvrdma_cmd_create_uc *cmd = &req.create_uc; | |
| 308 | + struct pvrdma_cmd_create_uc_resp *resp = &rsp.create_uc_resp; | |
| 309 | + struct pvrdma_alloc_ucontext_resp uresp; | |
| 310 | + int ret; | |
| 311 | + void *ptr; | |
| 312 | + | |
| 313 | + if (!vdev->ib_active) | |
| 314 | + return ERR_PTR(-EAGAIN); | |
| 315 | + | |
| 316 | + context = kmalloc(sizeof(*context), GFP_KERNEL); | |
| 317 | + if (!context) | |
| 318 | + return ERR_PTR(-ENOMEM); | |
| 319 | + | |
| 320 | + context->dev = vdev; | |
| 321 | + ret = pvrdma_uar_alloc(vdev, &context->uar); | |
| 322 | + if (ret) { | |
| 323 | + kfree(context); | |
| 324 | + return ERR_PTR(-ENOMEM); | |
| 325 | + } | |
| 326 | + | |
| 327 | + /* get ctx_handle from host */ | |
| 328 | + memset(cmd, 0, sizeof(*cmd)); | |
| 329 | + cmd->pfn = context->uar.pfn; | |
| 330 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_UC; | |
| 331 | + ret = pvrdma_cmd_post(vdev, &req, &rsp, PVRDMA_CMD_CREATE_UC_RESP); | |
| 332 | + if (ret < 0) { | |
| 333 | + dev_warn(&vdev->pdev->dev, | |
| 334 | + "could not create ucontext, error: %d\n", ret); | |
| 335 | + ptr = ERR_PTR(ret); | |
| 336 | + goto err; | |
| 337 | + } | |
| 338 | + | |
| 339 | + context->ctx_handle = resp->ctx_handle; | |
| 340 | + | |
| 341 | + /* copy back to user */ | |
| 342 | + uresp.qp_tab_size = vdev->dsr->caps.max_qp; | |
| 343 | + ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); | |
| 344 | + if (ret) { | |
| 345 | + pvrdma_uar_free(vdev, &context->uar); | |
| 346 | + context->ibucontext.device = ibdev; | |
| 347 | + pvrdma_dealloc_ucontext(&context->ibucontext); | |
| 348 | + return ERR_PTR(-EFAULT); | |
| 349 | + } | |
| 350 | + | |
| 351 | + return &context->ibucontext; | |
| 352 | + | |
| 353 | +err: | |
| 354 | + pvrdma_uar_free(vdev, &context->uar); | |
| 355 | + kfree(context); | |
| 356 | + return ptr; | |
| 357 | +} | |
| 358 | + | |
| 359 | +/** | |
| 360 | + * pvrdma_dealloc_ucontext - deallocate ucontext | |
| 361 | + * @ibcontext: the ucontext | |
| 362 | + * | |
| 363 | + * @return: 0 on success, otherwise errno. | |
| 364 | + */ | |
| 365 | +int pvrdma_dealloc_ucontext(struct ib_ucontext *ibcontext) | |
| 366 | +{ | |
| 367 | + struct pvrdma_ucontext *context = to_vucontext(ibcontext); | |
| 368 | + union pvrdma_cmd_req req; | |
| 369 | + struct pvrdma_cmd_destroy_uc *cmd = &req.destroy_uc; | |
| 370 | + int ret; | |
| 371 | + | |
| 372 | + memset(cmd, 0, sizeof(*cmd)); | |
| 373 | + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_UC; | |
| 374 | + cmd->ctx_handle = context->ctx_handle; | |
| 375 | + | |
| 376 | + ret = pvrdma_cmd_post(context->dev, &req, NULL, 0); | |
| 377 | + if (ret < 0) | |
| 378 | + dev_warn(&context->dev->pdev->dev, | |
| 379 | + "destroy ucontext failed, error: %d\n", ret); | |
| 380 | + | |
| 381 | + /* Free the UAR even if the device command failed */ | |
| 382 | + pvrdma_uar_free(to_vdev(ibcontext->device), &context->uar); | |
| 383 | + kfree(context); | |
| 384 | + | |
| 385 | + return ret; | |
| 386 | +} | |
| 387 | + | |
| 388 | +/** | |
| 389 | + * pvrdma_mmap - create mmap region | |
| 390 | + * @ibcontext: the user context | |
| 391 | + * @vma: the VMA | |
| 392 | + * | |
| 393 | + * @return: 0 on success, otherwise errno. | |
| 394 | + */ | |
| 395 | +int pvrdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) | |
| 396 | +{ | |
| 397 | + struct pvrdma_ucontext *context = to_vucontext(ibcontext); | |
| 398 | + unsigned long start = vma->vm_start; | |
| 399 | + unsigned long size = vma->vm_end - vma->vm_start; | |
| 400 | + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | |
| 401 | + | |
| 402 | + dev_dbg(&context->dev->pdev->dev, "create mmap region\n"); | |
| 403 | + | |
| 404 | + if ((size != PAGE_SIZE) || (offset & ~PAGE_MASK)) { | |
| 405 | + dev_warn(&context->dev->pdev->dev, | |
| 406 | + "invalid params for mmap region\n"); | |
| 407 | + return -EINVAL; | |
| 408 | + } | |
| 409 | + | |
| 410 | + /* Map UAR to kernel space, VM_LOCKED? */ | |
| 411 | + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; | |
| 412 | + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
| 413 | + if (io_remap_pfn_range(vma, start, context->uar.pfn, size, | |
| 414 | + vma->vm_page_prot)) | |
| 415 | + return -EAGAIN; | |
| 416 | + | |
| 417 | + return 0; | |
| 418 | +} | |
| 419 | + | |
| 420 | +/** | |
| 421 | + * pvrdma_alloc_pd - allocate protection domain | |
| 422 | + * @ibdev: the IB device | |
| 423 | + * @context: user context | |
| 424 | + * @udata: user data | |
| 425 | + * | |
| 426 | + * @return: the ib_pd protection domain pointer on success, otherwise errno. | |
| 427 | + */ | |
| 428 | +struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, | |
| 429 | + struct ib_ucontext *context, | |
| 430 | + struct ib_udata *udata) | |
| 431 | +{ | |
| 432 | + struct pvrdma_pd *pd; | |
| 433 | + struct pvrdma_dev *dev = to_vdev(ibdev); | |
| 434 | + union pvrdma_cmd_req req; | |
| 435 | + union pvrdma_cmd_resp rsp; | |
| 436 | + struct pvrdma_cmd_create_pd *cmd = &req.create_pd; | |
| 437 | + struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp; | |
| 438 | + int ret; | |
| 439 | + void *ptr; | |
| 440 | + | |
| 441 | + /* Check allowed max pds */ | |
| 442 | + if (!atomic_add_unless(&dev->num_pds, 1, dev->dsr->caps.max_pd)) | |
| 443 | + return ERR_PTR(-ENOMEM); | |
| 444 | + | |
| 445 | + pd = kmalloc(sizeof(*pd), GFP_KERNEL); | |
| 446 | + if (!pd) { | |
| 447 | + ptr = ERR_PTR(-ENOMEM); | |
| 448 | + goto err; | |
| 449 | + } | |
| 450 | + | |
| 451 | + memset(cmd, 0, sizeof(*cmd)); | |
| 452 | + cmd->hdr.cmd = PVRDMA_CMD_CREATE_PD; | |
| 453 | + cmd->ctx_handle = (context) ? to_vucontext(context)->ctx_handle : 0; | |
| 454 | + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_PD_RESP); | |
| 455 | + if (ret < 0) { | |
| 456 | + dev_warn(&dev->pdev->dev, | |
| 457 | + "failed to allocate protection domain, error: %d\n", | |
| 458 | + ret); | |
| 459 | + ptr = ERR_PTR(ret); | |
| 460 | + goto freepd; | |
| 461 | + } | |
| 462 | + | |
| 463 | + pd->privileged = !context; | |
| 464 | + pd->pd_handle = resp->pd_handle; | |
| 465 | + pd->pdn = resp->pd_handle; | |
| 466 | + | |
| 467 | + if (context) { | |
| 468 | + if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) { | |
| 469 | + dev_warn(&dev->pdev->dev, | |
| 470 | + "failed to copy back protection domain\n"); | |
| 471 | + pvrdma_dealloc_pd(&pd->ibpd); | |
| 472 | + return ERR_PTR(-EFAULT); | |
| 473 | + } | |
| 474 | + } | |
| 475 | + | |
| 476 | + /* u32 pd handle */ | |
| 477 | + return &pd->ibpd; | |
| 478 | + | |
| 479 | +freepd: | |
| 480 | + kfree(pd); | |
| 481 | +err: | |
| 482 | + atomic_dec(&dev->num_pds); | |
| 483 | + return ptr; | |
| 484 | +} | |
| 485 | + | |
| 486 | +/** | |
| 487 | + * pvrdma_dealloc_pd - deallocate protection domain | |
| 488 | + * @pd: the protection domain to be released | |
| 489 | + * | |
| 490 | + * @return: 0 on success, otherwise errno. | |
| 491 | + */ | |
| 492 | +int pvrdma_dealloc_pd(struct ib_pd *pd) | |
| 493 | +{ | |
| 494 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 495 | + union pvrdma_cmd_req req; | |
| 496 | + struct pvrdma_cmd_destroy_pd *cmd = &req.destroy_pd; | |
| 497 | + int ret; | |
| 498 | + | |
| 499 | + memset(cmd, 0, sizeof(*cmd)); | |
| 500 | + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_PD; | |
| 501 | + cmd->pd_handle = to_vpd(pd)->pd_handle; | |
| 502 | + | |
| 503 | + ret = pvrdma_cmd_post(dev, &req, NULL, 0); | |
| 504 | + if (ret) | |
| 505 | + dev_warn(&dev->pdev->dev, | |
| 506 | + "could not dealloc protection domain, error: %d\n", | |
| 507 | + ret); | |
| 508 | + | |
| 509 | + kfree(to_vpd(pd)); | |
| 510 | + atomic_dec(&dev->num_pds); | |
| 511 | + | |
| 512 | + return 0; | |
| 513 | +} | |
| 514 | + | |
| 515 | +/** | |
| 516 | + * pvrdma_create_ah - create an address handle | |
| 517 | + * @pd: the protection domain | |
| 518 | + * @ah_attr: the attributes of the AH | |
| 519 | + * @udata: user data blob | |
| 520 | + * | |
| 521 | + * @return: the ib_ah pointer on success, otherwise errno. | |
| 522 | + */ | |
| 523 | +struct ib_ah *pvrdma_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | |
| 524 | + struct ib_udata *udata) | |
| 525 | +{ | |
| 526 | + struct pvrdma_dev *dev = to_vdev(pd->device); | |
| 527 | + struct pvrdma_ah *ah; | |
| 528 | + enum rdma_link_layer ll; | |
| 529 | + | |
| 530 | + if (!(ah_attr->ah_flags & IB_AH_GRH)) | |
| 531 | + return ERR_PTR(-EINVAL); | |
| 532 | + | |
| 533 | + ll = rdma_port_get_link_layer(pd->device, ah_attr->port_num); | |
| 534 | + | |
| 535 | + if (ll != IB_LINK_LAYER_ETHERNET || | |
| 536 | + rdma_is_multicast_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) | |
| 537 | + return ERR_PTR(-EINVAL); | |
| 538 | + | |
| 539 | + if (!atomic_add_unless(&dev->num_ahs, 1, dev->dsr->caps.max_ah)) | |
| 540 | + return ERR_PTR(-ENOMEM); | |
| 541 | + | |
| 542 | + ah = kzalloc(sizeof(*ah), GFP_KERNEL); | |
| 543 | + if (!ah) { | |
| 544 | + atomic_dec(&dev->num_ahs); | |
| 545 | + return ERR_PTR(-ENOMEM); | |
| 546 | + } | |
| 547 | + | |
| 548 | + ah->av.port_pd = to_vpd(pd)->pd_handle | (ah_attr->port_num << 24); | |
| 549 | + ah->av.src_path_bits = ah_attr->src_path_bits; | |
| 550 | + ah->av.src_path_bits |= 0x80; | |
| 551 | + ah->av.gid_index = ah_attr->grh.sgid_index; | |
| 552 | + ah->av.hop_limit = ah_attr->grh.hop_limit; | |
| 553 | + ah->av.sl_tclass_flowlabel = (ah_attr->grh.traffic_class << 20) | | |
| 554 | + ah_attr->grh.flow_label; | |
| 555 | + memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16); | |
| 556 | + memcpy(ah->av.dmac, ah_attr->dmac, 6); | |
| 557 | + | |
| 558 | + ah->ibah.device = pd->device; | |
| 559 | + ah->ibah.pd = pd; | |
| 560 | + ah->ibah.uobject = NULL; | |
| 561 | + | |
| 562 | + return &ah->ibah; | |
| 563 | +} | |
| 564 | + | |
| 565 | +/** | |
| 566 | + * pvrdma_destroy_ah - destroy an address handle | |
| 567 | + * @ah: the address handle to destroyed | |
| 568 | + * | |
| 569 | + * @return: 0 on success. | |
| 570 | + */ | |
| 571 | +int pvrdma_destroy_ah(struct ib_ah *ah) | |
| 572 | +{ | |
| 573 | + struct pvrdma_dev *dev = to_vdev(ah->device); | |
| 574 | + | |
| 575 | + kfree(to_vah(ah)); | |
| 576 | + atomic_dec(&dev->num_ahs); | |
| 577 | + | |
| 578 | + return 0; | |
| 579 | +} | |
| @@ -0,0 +1,436 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#ifndef __PVRDMA_VERBS_H__ | |
| 47 | +#define __PVRDMA_VERBS_H__ | |
| 48 | + | |
| 49 | +#include <linux/types.h> | |
| 50 | + | |
| 51 | +union pvrdma_gid { | |
| 52 | + u8 raw[16]; | |
| 53 | + struct { | |
| 54 | + __be64 subnet_prefix; | |
| 55 | + __be64 interface_id; | |
| 56 | + } global; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +enum pvrdma_link_layer { | |
| 60 | + PVRDMA_LINK_LAYER_UNSPECIFIED, | |
| 61 | + PVRDMA_LINK_LAYER_INFINIBAND, | |
| 62 | + PVRDMA_LINK_LAYER_ETHERNET, | |
| 63 | +}; | |
| 64 | + | |
| 65 | +enum pvrdma_mtu { | |
| 66 | + PVRDMA_MTU_256 = 1, | |
| 67 | + PVRDMA_MTU_512 = 2, | |
| 68 | + PVRDMA_MTU_1024 = 3, | |
| 69 | + PVRDMA_MTU_2048 = 4, | |
| 70 | + PVRDMA_MTU_4096 = 5, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +static inline int pvrdma_mtu_enum_to_int(enum pvrdma_mtu mtu) | |
| 74 | +{ | |
| 75 | + switch (mtu) { | |
| 76 | + case PVRDMA_MTU_256: return 256; | |
| 77 | + case PVRDMA_MTU_512: return 512; | |
| 78 | + case PVRDMA_MTU_1024: return 1024; | |
| 79 | + case PVRDMA_MTU_2048: return 2048; | |
| 80 | + case PVRDMA_MTU_4096: return 4096; | |
| 81 | + default: return -1; | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | +static inline enum pvrdma_mtu pvrdma_mtu_int_to_enum(int mtu) | |
| 86 | +{ | |
| 87 | + switch (mtu) { | |
| 88 | + case 256: return PVRDMA_MTU_256; | |
| 89 | + case 512: return PVRDMA_MTU_512; | |
| 90 | + case 1024: return PVRDMA_MTU_1024; | |
| 91 | + case 2048: return PVRDMA_MTU_2048; | |
| 92 | + case 4096: | |
| 93 | + default: return PVRDMA_MTU_4096; | |
| 94 | + } | |
| 95 | +} | |
| 96 | + | |
| 97 | +enum pvrdma_port_state { | |
| 98 | + PVRDMA_PORT_NOP = 0, | |
| 99 | + PVRDMA_PORT_DOWN = 1, | |
| 100 | + PVRDMA_PORT_INIT = 2, | |
| 101 | + PVRDMA_PORT_ARMED = 3, | |
| 102 | + PVRDMA_PORT_ACTIVE = 4, | |
| 103 | + PVRDMA_PORT_ACTIVE_DEFER = 5, | |
| 104 | +}; | |
| 105 | + | |
| 106 | +enum pvrdma_port_cap_flags { | |
| 107 | + PVRDMA_PORT_SM = 1 << 1, | |
| 108 | + PVRDMA_PORT_NOTICE_SUP = 1 << 2, | |
| 109 | + PVRDMA_PORT_TRAP_SUP = 1 << 3, | |
| 110 | + PVRDMA_PORT_OPT_IPD_SUP = 1 << 4, | |
| 111 | + PVRDMA_PORT_AUTO_MIGR_SUP = 1 << 5, | |
| 112 | + PVRDMA_PORT_SL_MAP_SUP = 1 << 6, | |
| 113 | + PVRDMA_PORT_MKEY_NVRAM = 1 << 7, | |
| 114 | + PVRDMA_PORT_PKEY_NVRAM = 1 << 8, | |
| 115 | + PVRDMA_PORT_LED_INFO_SUP = 1 << 9, | |
| 116 | + PVRDMA_PORT_SM_DISABLED = 1 << 10, | |
| 117 | + PVRDMA_PORT_SYS_IMAGE_GUID_SUP = 1 << 11, | |
| 118 | + PVRDMA_PORT_PKEY_SW_EXT_PORT_TRAP_SUP = 1 << 12, | |
| 119 | + PVRDMA_PORT_EXTENDED_SPEEDS_SUP = 1 << 14, | |
| 120 | + PVRDMA_PORT_CM_SUP = 1 << 16, | |
| 121 | + PVRDMA_PORT_SNMP_TUNNEL_SUP = 1 << 17, | |
| 122 | + PVRDMA_PORT_REINIT_SUP = 1 << 18, | |
| 123 | + PVRDMA_PORT_DEVICE_MGMT_SUP = 1 << 19, | |
| 124 | + PVRDMA_PORT_VENDOR_CLASS_SUP = 1 << 20, | |
| 125 | + PVRDMA_PORT_DR_NOTICE_SUP = 1 << 21, | |
| 126 | + PVRDMA_PORT_CAP_MASK_NOTICE_SUP = 1 << 22, | |
| 127 | + PVRDMA_PORT_BOOT_MGMT_SUP = 1 << 23, | |
| 128 | + PVRDMA_PORT_LINK_LATENCY_SUP = 1 << 24, | |
| 129 | + PVRDMA_PORT_CLIENT_REG_SUP = 1 << 25, | |
| 130 | + PVRDMA_PORT_IP_BASED_GIDS = 1 << 26, | |
| 131 | + PVRDMA_PORT_CAP_FLAGS_MAX = PVRDMA_PORT_IP_BASED_GIDS, | |
| 132 | +}; | |
| 133 | + | |
| 134 | +enum pvrdma_port_width { | |
| 135 | + PVRDMA_WIDTH_1X = 1, | |
| 136 | + PVRDMA_WIDTH_4X = 2, | |
| 137 | + PVRDMA_WIDTH_8X = 4, | |
| 138 | + PVRDMA_WIDTH_12X = 8, | |
| 139 | +}; | |
| 140 | + | |
| 141 | +static inline int pvrdma_width_enum_to_int(enum pvrdma_port_width width) | |
| 142 | +{ | |
| 143 | + switch (width) { | |
| 144 | + case PVRDMA_WIDTH_1X: return 1; | |
| 145 | + case PVRDMA_WIDTH_4X: return 4; | |
| 146 | + case PVRDMA_WIDTH_8X: return 8; | |
| 147 | + case PVRDMA_WIDTH_12X: return 12; | |
| 148 | + default: return -1; | |
| 149 | + } | |
| 150 | +} | |
| 151 | + | |
| 152 | +enum pvrdma_port_speed { | |
| 153 | + PVRDMA_SPEED_SDR = 1, | |
| 154 | + PVRDMA_SPEED_DDR = 2, | |
| 155 | + PVRDMA_SPEED_QDR = 4, | |
| 156 | + PVRDMA_SPEED_FDR10 = 8, | |
| 157 | + PVRDMA_SPEED_FDR = 16, | |
| 158 | + PVRDMA_SPEED_EDR = 32, | |
| 159 | +}; | |
| 160 | + | |
| 161 | +struct pvrdma_port_attr { | |
| 162 | + enum pvrdma_port_state state; | |
| 163 | + enum pvrdma_mtu max_mtu; | |
| 164 | + enum pvrdma_mtu active_mtu; | |
| 165 | + u32 gid_tbl_len; | |
| 166 | + u32 port_cap_flags; | |
| 167 | + u32 max_msg_sz; | |
| 168 | + u32 bad_pkey_cntr; | |
| 169 | + u32 qkey_viol_cntr; | |
| 170 | + u16 pkey_tbl_len; | |
| 171 | + u16 lid; | |
| 172 | + u16 sm_lid; | |
| 173 | + u8 lmc; | |
| 174 | + u8 max_vl_num; | |
| 175 | + u8 sm_sl; | |
| 176 | + u8 subnet_timeout; | |
| 177 | + u8 init_type_reply; | |
| 178 | + u8 active_width; | |
| 179 | + u8 active_speed; | |
| 180 | + u8 phys_state; | |
| 181 | + u8 reserved[2]; | |
| 182 | +}; | |
| 183 | + | |
| 184 | +struct pvrdma_global_route { | |
| 185 | + union pvrdma_gid dgid; | |
| 186 | + u32 flow_label; | |
| 187 | + u8 sgid_index; | |
| 188 | + u8 hop_limit; | |
| 189 | + u8 traffic_class; | |
| 190 | + u8 reserved; | |
| 191 | +}; | |
| 192 | + | |
| 193 | +struct pvrdma_grh { | |
| 194 | + __be32 version_tclass_flow; | |
| 195 | + __be16 paylen; | |
| 196 | + u8 next_hdr; | |
| 197 | + u8 hop_limit; | |
| 198 | + union pvrdma_gid sgid; | |
| 199 | + union pvrdma_gid dgid; | |
| 200 | +}; | |
| 201 | + | |
| 202 | +enum pvrdma_ah_flags { | |
| 203 | + PVRDMA_AH_GRH = 1, | |
| 204 | +}; | |
| 205 | + | |
| 206 | +enum pvrdma_rate { | |
| 207 | + PVRDMA_RATE_PORT_CURRENT = 0, | |
| 208 | + PVRDMA_RATE_2_5_GBPS = 2, | |
| 209 | + PVRDMA_RATE_5_GBPS = 5, | |
| 210 | + PVRDMA_RATE_10_GBPS = 3, | |
| 211 | + PVRDMA_RATE_20_GBPS = 6, | |
| 212 | + PVRDMA_RATE_30_GBPS = 4, | |
| 213 | + PVRDMA_RATE_40_GBPS = 7, | |
| 214 | + PVRDMA_RATE_60_GBPS = 8, | |
| 215 | + PVRDMA_RATE_80_GBPS = 9, | |
| 216 | + PVRDMA_RATE_120_GBPS = 10, | |
| 217 | + PVRDMA_RATE_14_GBPS = 11, | |
| 218 | + PVRDMA_RATE_56_GBPS = 12, | |
| 219 | + PVRDMA_RATE_112_GBPS = 13, | |
| 220 | + PVRDMA_RATE_168_GBPS = 14, | |
| 221 | + PVRDMA_RATE_25_GBPS = 15, | |
| 222 | + PVRDMA_RATE_100_GBPS = 16, | |
| 223 | + PVRDMA_RATE_200_GBPS = 17, | |
| 224 | + PVRDMA_RATE_300_GBPS = 18, | |
| 225 | +}; | |
| 226 | + | |
| 227 | +struct pvrdma_ah_attr { | |
| 228 | + struct pvrdma_global_route grh; | |
| 229 | + u16 dlid; | |
| 230 | + u16 vlan_id; | |
| 231 | + u8 sl; | |
| 232 | + u8 src_path_bits; | |
| 233 | + u8 static_rate; | |
| 234 | + u8 ah_flags; | |
| 235 | + u8 port_num; | |
| 236 | + u8 dmac[6]; | |
| 237 | + u8 reserved; | |
| 238 | +}; | |
| 239 | + | |
| 240 | +enum pvrdma_cq_notify_flags { | |
| 241 | + PVRDMA_CQ_SOLICITED = 1 << 0, | |
| 242 | + PVRDMA_CQ_NEXT_COMP = 1 << 1, | |
| 243 | + PVRDMA_CQ_SOLICITED_MASK = PVRDMA_CQ_SOLICITED | | |
| 244 | + PVRDMA_CQ_NEXT_COMP, | |
| 245 | + PVRDMA_CQ_REPORT_MISSED_EVENTS = 1 << 2, | |
| 246 | +}; | |
| 247 | + | |
| 248 | +struct pvrdma_qp_cap { | |
| 249 | + u32 max_send_wr; | |
| 250 | + u32 max_recv_wr; | |
| 251 | + u32 max_send_sge; | |
| 252 | + u32 max_recv_sge; | |
| 253 | + u32 max_inline_data; | |
| 254 | + u32 reserved; | |
| 255 | +}; | |
| 256 | + | |
| 257 | +enum pvrdma_sig_type { | |
| 258 | + PVRDMA_SIGNAL_ALL_WR, | |
| 259 | + PVRDMA_SIGNAL_REQ_WR, | |
| 260 | +}; | |
| 261 | + | |
| 262 | +enum pvrdma_qp_type { | |
| 263 | + PVRDMA_QPT_SMI, | |
| 264 | + PVRDMA_QPT_GSI, | |
| 265 | + PVRDMA_QPT_RC, | |
| 266 | + PVRDMA_QPT_UC, | |
| 267 | + PVRDMA_QPT_UD, | |
| 268 | + PVRDMA_QPT_RAW_IPV6, | |
| 269 | + PVRDMA_QPT_RAW_ETHERTYPE, | |
| 270 | + PVRDMA_QPT_RAW_PACKET = 8, | |
| 271 | + PVRDMA_QPT_XRC_INI = 9, | |
| 272 | + PVRDMA_QPT_XRC_TGT, | |
| 273 | + PVRDMA_QPT_MAX, | |
| 274 | +}; | |
| 275 | + | |
| 276 | +enum pvrdma_qp_create_flags { | |
| 277 | + PVRDMA_QP_CREATE_IPOPVRDMA_UD_LSO = 1 << 0, | |
| 278 | + PVRDMA_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1, | |
| 279 | +}; | |
| 280 | + | |
| 281 | +enum pvrdma_qp_attr_mask { | |
| 282 | + PVRDMA_QP_STATE = 1 << 0, | |
| 283 | + PVRDMA_QP_CUR_STATE = 1 << 1, | |
| 284 | + PVRDMA_QP_EN_SQD_ASYNC_NOTIFY = 1 << 2, | |
| 285 | + PVRDMA_QP_ACCESS_FLAGS = 1 << 3, | |
| 286 | + PVRDMA_QP_PKEY_INDEX = 1 << 4, | |
| 287 | + PVRDMA_QP_PORT = 1 << 5, | |
| 288 | + PVRDMA_QP_QKEY = 1 << 6, | |
| 289 | + PVRDMA_QP_AV = 1 << 7, | |
| 290 | + PVRDMA_QP_PATH_MTU = 1 << 8, | |
| 291 | + PVRDMA_QP_TIMEOUT = 1 << 9, | |
| 292 | + PVRDMA_QP_RETRY_CNT = 1 << 10, | |
| 293 | + PVRDMA_QP_RNR_RETRY = 1 << 11, | |
| 294 | + PVRDMA_QP_RQ_PSN = 1 << 12, | |
| 295 | + PVRDMA_QP_MAX_QP_RD_ATOMIC = 1 << 13, | |
| 296 | + PVRDMA_QP_ALT_PATH = 1 << 14, | |
| 297 | + PVRDMA_QP_MIN_RNR_TIMER = 1 << 15, | |
| 298 | + PVRDMA_QP_SQ_PSN = 1 << 16, | |
| 299 | + PVRDMA_QP_MAX_DEST_RD_ATOMIC = 1 << 17, | |
| 300 | + PVRDMA_QP_PATH_MIG_STATE = 1 << 18, | |
| 301 | + PVRDMA_QP_CAP = 1 << 19, | |
| 302 | + PVRDMA_QP_DEST_QPN = 1 << 20, | |
| 303 | + PVRDMA_QP_ATTR_MASK_MAX = PVRDMA_QP_DEST_QPN, | |
| 304 | +}; | |
| 305 | + | |
| 306 | +enum pvrdma_qp_state { | |
| 307 | + PVRDMA_QPS_RESET, | |
| 308 | + PVRDMA_QPS_INIT, | |
| 309 | + PVRDMA_QPS_RTR, | |
| 310 | + PVRDMA_QPS_RTS, | |
| 311 | + PVRDMA_QPS_SQD, | |
| 312 | + PVRDMA_QPS_SQE, | |
| 313 | + PVRDMA_QPS_ERR, | |
| 314 | +}; | |
| 315 | + | |
| 316 | +enum pvrdma_mig_state { | |
| 317 | + PVRDMA_MIG_MIGRATED, | |
| 318 | + PVRDMA_MIG_REARM, | |
| 319 | + PVRDMA_MIG_ARMED, | |
| 320 | +}; | |
| 321 | + | |
| 322 | +enum pvrdma_mw_type { | |
| 323 | + PVRDMA_MW_TYPE_1 = 1, | |
| 324 | + PVRDMA_MW_TYPE_2 = 2, | |
| 325 | +}; | |
| 326 | + | |
| 327 | +struct pvrdma_qp_attr { | |
| 328 | + enum pvrdma_qp_state qp_state; | |
| 329 | + enum pvrdma_qp_state cur_qp_state; | |
| 330 | + enum pvrdma_mtu path_mtu; | |
| 331 | + enum pvrdma_mig_state path_mig_state; | |
| 332 | + u32 qkey; | |
| 333 | + u32 rq_psn; | |
| 334 | + u32 sq_psn; | |
| 335 | + u32 dest_qp_num; | |
| 336 | + u32 qp_access_flags; | |
| 337 | + u16 pkey_index; | |
| 338 | + u16 alt_pkey_index; | |
| 339 | + u8 en_sqd_async_notify; | |
| 340 | + u8 sq_draining; | |
| 341 | + u8 max_rd_atomic; | |
| 342 | + u8 max_dest_rd_atomic; | |
| 343 | + u8 min_rnr_timer; | |
| 344 | + u8 port_num; | |
| 345 | + u8 timeout; | |
| 346 | + u8 retry_cnt; | |
| 347 | + u8 rnr_retry; | |
| 348 | + u8 alt_port_num; | |
| 349 | + u8 alt_timeout; | |
| 350 | + u8 reserved[5]; | |
| 351 | + struct pvrdma_qp_cap cap; | |
| 352 | + struct pvrdma_ah_attr ah_attr; | |
| 353 | + struct pvrdma_ah_attr alt_ah_attr; | |
| 354 | +}; | |
| 355 | + | |
| 356 | +enum pvrdma_send_flags { | |
| 357 | + PVRDMA_SEND_FENCE = 1 << 0, | |
| 358 | + PVRDMA_SEND_SIGNALED = 1 << 1, | |
| 359 | + PVRDMA_SEND_SOLICITED = 1 << 2, | |
| 360 | + PVRDMA_SEND_INLINE = 1 << 3, | |
| 361 | + PVRDMA_SEND_IP_CSUM = 1 << 4, | |
| 362 | + PVRDMA_SEND_FLAGS_MAX = PVRDMA_SEND_IP_CSUM, | |
| 363 | +}; | |
| 364 | + | |
| 365 | +enum pvrdma_access_flags { | |
| 366 | + PVRDMA_ACCESS_LOCAL_WRITE = 1 << 0, | |
| 367 | + PVRDMA_ACCESS_REMOTE_WRITE = 1 << 1, | |
| 368 | + PVRDMA_ACCESS_REMOTE_READ = 1 << 2, | |
| 369 | + PVRDMA_ACCESS_REMOTE_ATOMIC = 1 << 3, | |
| 370 | + PVRDMA_ACCESS_MW_BIND = 1 << 4, | |
| 371 | + PVRDMA_ZERO_BASED = 1 << 5, | |
| 372 | + PVRDMA_ACCESS_ON_DEMAND = 1 << 6, | |
| 373 | + PVRDMA_ACCESS_FLAGS_MAX = PVRDMA_ACCESS_ON_DEMAND, | |
| 374 | +}; | |
| 375 | + | |
| 376 | +int pvrdma_query_device(struct ib_device *ibdev, | |
| 377 | + struct ib_device_attr *props, | |
| 378 | + struct ib_udata *udata); | |
| 379 | +int pvrdma_query_port(struct ib_device *ibdev, u8 port, | |
| 380 | + struct ib_port_attr *props); | |
| 381 | +int pvrdma_query_gid(struct ib_device *ibdev, u8 port, | |
| 382 | + int index, union ib_gid *gid); | |
| 383 | +int pvrdma_query_pkey(struct ib_device *ibdev, u8 port, | |
| 384 | + u16 index, u16 *pkey); | |
| 385 | +enum rdma_link_layer pvrdma_port_link_layer(struct ib_device *ibdev, | |
| 386 | + u8 port); | |
| 387 | +int pvrdma_modify_device(struct ib_device *ibdev, int mask, | |
| 388 | + struct ib_device_modify *props); | |
| 389 | +int pvrdma_modify_port(struct ib_device *ibdev, u8 port, | |
| 390 | + int mask, struct ib_port_modify *props); | |
| 391 | +int pvrdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); | |
| 392 | +struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, | |
| 393 | + struct ib_udata *udata); | |
| 394 | +int pvrdma_dealloc_ucontext(struct ib_ucontext *context); | |
| 395 | +struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, | |
| 396 | + struct ib_ucontext *context, | |
| 397 | + struct ib_udata *udata); | |
| 398 | +int pvrdma_dealloc_pd(struct ib_pd *ibpd); | |
| 399 | +struct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc); | |
| 400 | +struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, | |
| 401 | + u64 virt_addr, int access_flags, | |
| 402 | + struct ib_udata *udata); | |
| 403 | +int pvrdma_dereg_mr(struct ib_mr *mr); | |
| 404 | +struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, | |
| 405 | + u32 max_num_sg); | |
| 406 | +int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, | |
| 407 | + int sg_nents, unsigned int *sg_offset); | |
| 408 | +int pvrdma_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); | |
| 409 | +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, | |
| 410 | + struct ib_udata *udata); | |
| 411 | +struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, | |
| 412 | + const struct ib_cq_init_attr *attr, | |
| 413 | + struct ib_ucontext *context, | |
| 414 | + struct ib_udata *udata); | |
| 415 | +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, | |
| 416 | + struct ib_udata *udata); | |
| 417 | +int pvrdma_destroy_cq(struct ib_cq *cq); | |
| 418 | +int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); | |
| 419 | +int pvrdma_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); | |
| 420 | +struct ib_ah *pvrdma_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | |
| 421 | + struct ib_udata *udata); | |
| 422 | +int pvrdma_destroy_ah(struct ib_ah *ah); | |
| 423 | +struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, | |
| 424 | + struct ib_qp_init_attr *init_attr, | |
| 425 | + struct ib_udata *udata); | |
| 426 | +int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |
| 427 | + int attr_mask, struct ib_udata *udata); | |
| 428 | +int pvrdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, | |
| 429 | + int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr); | |
| 430 | +int pvrdma_destroy_qp(struct ib_qp *qp); | |
| 431 | +int pvrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |
| 432 | + struct ib_send_wr **bad_wr); | |
| 433 | +int pvrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |
| 434 | + struct ib_recv_wr **bad_wr); | |
| 435 | + | |
| 436 | +#endif /* __PVRDMA_VERBS_H__ */ | |
| @@ -119,9 +119,8 @@ enum { · 118 unmodified lines | ||
| 119 | 119 | }; |
| 120 | 120 | |
| 121 | 121 | /* |
| 122 | − * PCI vendor and device IDs. | |
| 122 | + * Maximum devices supported. | |
| 123 | 123 | */ |
| 124 | −#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 | |
| 125 | 124 | #define MAX_ETHERNET_CARDS 10 |
| 126 | 125 | #define MAX_PCI_PASSTHRU_DEVICE 6 |
| 127 | 126 | |
| @@ -2251,6 +2251,7 @@ · 2250 unmodified lines | ||
| 2251 | 2251 | #define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 |
| 2252 | 2252 | |
| 2253 | 2253 | #define PCI_VENDOR_ID_VMWARE 0x15ad |
| 2254 | +#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07b0 | |
| 2254 | 2255 | |
| 2255 | 2256 | #define PCI_VENDOR_ID_ZOLTRIX 0x15b0 |
| 2256 | 2257 | #define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 |
| @@ -15,3 +15,4 @@ header-y += mthca-abi.h · 14 unmodified lines | ||
| 15 | 15 | header-y += nes-abi.h |
| 16 | 16 | header-y += ocrdma-abi.h |
| 17 | 17 | header-y += hns-abi.h |
| 18 | +header-y += vmw_pvrdma-abi.h | |
| @@ -0,0 +1,289 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of EITHER the GNU General Public License | |
| 6 | + * version 2 as published by the Free Software Foundation or the BSD | |
| 7 | + * 2-Clause License. This program is distributed in the hope that it | |
| 8 | + * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | |
| 9 | + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| 10 | + * See the GNU General Public License version 2 for more details at | |
| 11 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | |
| 12 | + * | |
| 13 | + * You should have received a copy of the GNU General Public License | |
| 14 | + * along with this program available in the file COPYING in the main | |
| 15 | + * directory of this source tree. | |
| 16 | + * | |
| 17 | + * The BSD 2-Clause License | |
| 18 | + * | |
| 19 | + * Redistribution and use in source and binary forms, with or | |
| 20 | + * without modification, are permitted provided that the following | |
| 21 | + * conditions are met: | |
| 22 | + * | |
| 23 | + * - Redistributions of source code must retain the above | |
| 24 | + * copyright notice, this list of conditions and the following | |
| 25 | + * disclaimer. | |
| 26 | + * | |
| 27 | + * - Redistributions in binary form must reproduce the above | |
| 28 | + * copyright notice, this list of conditions and the following | |
| 29 | + * disclaimer in the documentation and/or other materials | |
| 30 | + * provided with the distribution. | |
| 31 | + * | |
| 32 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 33 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 34 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 35 | + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 36 | + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
| 37 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 38 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 39 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 40 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 41 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 42 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 43 | + * OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 44 | + */ | |
| 45 | + | |
| 46 | +#ifndef __VMW_PVRDMA_ABI_H__ | |
| 47 | +#define __VMW_PVRDMA_ABI_H__ | |
| 48 | + | |
| 49 | +#include <linux/types.h> | |
| 50 | + | |
| 51 | +#define PVRDMA_UVERBS_ABI_VERSION 3 /* ABI Version. */ | |
| 52 | +#define PVRDMA_UAR_HANDLE_MASK 0x00FFFFFF /* Bottom 24 bits. */ | |
| 53 | +#define PVRDMA_UAR_QP_OFFSET 0 /* QP doorbell. */ | |
| 54 | +#define PVRDMA_UAR_QP_SEND BIT(30) /* Send bit. */ | |
| 55 | +#define PVRDMA_UAR_QP_RECV BIT(31) /* Recv bit. */ | |
| 56 | +#define PVRDMA_UAR_CQ_OFFSET 4 /* CQ doorbell. */ | |
| 57 | +#define PVRDMA_UAR_CQ_ARM_SOL BIT(29) /* Arm solicited bit. */ | |
| 58 | +#define PVRDMA_UAR_CQ_ARM BIT(30) /* Arm bit. */ | |
| 59 | +#define PVRDMA_UAR_CQ_POLL BIT(31) /* Poll bit. */ | |
| 60 | + | |
| 61 | +enum pvrdma_wr_opcode { | |
| 62 | + PVRDMA_WR_RDMA_WRITE, | |
| 63 | + PVRDMA_WR_RDMA_WRITE_WITH_IMM, | |
| 64 | + PVRDMA_WR_SEND, | |
| 65 | + PVRDMA_WR_SEND_WITH_IMM, | |
| 66 | + PVRDMA_WR_RDMA_READ, | |
| 67 | + PVRDMA_WR_ATOMIC_CMP_AND_SWP, | |
| 68 | + PVRDMA_WR_ATOMIC_FETCH_AND_ADD, | |
| 69 | + PVRDMA_WR_LSO, | |
| 70 | + PVRDMA_WR_SEND_WITH_INV, | |
| 71 | + PVRDMA_WR_RDMA_READ_WITH_INV, | |
| 72 | + PVRDMA_WR_LOCAL_INV, | |
| 73 | + PVRDMA_WR_FAST_REG_MR, | |
| 74 | + PVRDMA_WR_MASKED_ATOMIC_CMP_AND_SWP, | |
| 75 | + PVRDMA_WR_MASKED_ATOMIC_FETCH_AND_ADD, | |
| 76 | + PVRDMA_WR_BIND_MW, | |
| 77 | + PVRDMA_WR_REG_SIG_MR, | |
| 78 | +}; | |
| 79 | + | |
| 80 | +enum pvrdma_wc_status { | |
| 81 | + PVRDMA_WC_SUCCESS, | |
| 82 | + PVRDMA_WC_LOC_LEN_ERR, | |
| 83 | + PVRDMA_WC_LOC_QP_OP_ERR, | |
| 84 | + PVRDMA_WC_LOC_EEC_OP_ERR, | |
| 85 | + PVRDMA_WC_LOC_PROT_ERR, | |
| 86 | + PVRDMA_WC_WR_FLUSH_ERR, | |
| 87 | + PVRDMA_WC_MW_BIND_ERR, | |
| 88 | + PVRDMA_WC_BAD_RESP_ERR, | |
| 89 | + PVRDMA_WC_LOC_ACCESS_ERR, | |
| 90 | + PVRDMA_WC_REM_INV_REQ_ERR, | |
| 91 | + PVRDMA_WC_REM_ACCESS_ERR, | |
| 92 | + PVRDMA_WC_REM_OP_ERR, | |
| 93 | + PVRDMA_WC_RETRY_EXC_ERR, | |
| 94 | + PVRDMA_WC_RNR_RETRY_EXC_ERR, | |
| 95 | + PVRDMA_WC_LOC_RDD_VIOL_ERR, | |
| 96 | + PVRDMA_WC_REM_INV_RD_REQ_ERR, | |
| 97 | + PVRDMA_WC_REM_ABORT_ERR, | |
| 98 | + PVRDMA_WC_INV_EECN_ERR, | |
| 99 | + PVRDMA_WC_INV_EEC_STATE_ERR, | |
| 100 | + PVRDMA_WC_FATAL_ERR, | |
| 101 | + PVRDMA_WC_RESP_TIMEOUT_ERR, | |
| 102 | + PVRDMA_WC_GENERAL_ERR, | |
| 103 | +}; | |
| 104 | + | |
| 105 | +enum pvrdma_wc_opcode { | |
| 106 | + PVRDMA_WC_SEND, | |
| 107 | + PVRDMA_WC_RDMA_WRITE, | |
| 108 | + PVRDMA_WC_RDMA_READ, | |
| 109 | + PVRDMA_WC_COMP_SWAP, | |
| 110 | + PVRDMA_WC_FETCH_ADD, | |
| 111 | + PVRDMA_WC_BIND_MW, | |
| 112 | + PVRDMA_WC_LSO, | |
| 113 | + PVRDMA_WC_LOCAL_INV, | |
| 114 | + PVRDMA_WC_FAST_REG_MR, | |
| 115 | + PVRDMA_WC_MASKED_COMP_SWAP, | |
| 116 | + PVRDMA_WC_MASKED_FETCH_ADD, | |
| 117 | + PVRDMA_WC_RECV = 1 << 7, | |
| 118 | + PVRDMA_WC_RECV_RDMA_WITH_IMM, | |
| 119 | +}; | |
| 120 | + | |
| 121 | +enum pvrdma_wc_flags { | |
| 122 | + PVRDMA_WC_GRH = 1 << 0, | |
| 123 | + PVRDMA_WC_WITH_IMM = 1 << 1, | |
| 124 | + PVRDMA_WC_WITH_INVALIDATE = 1 << 2, | |
| 125 | + PVRDMA_WC_IP_CSUM_OK = 1 << 3, | |
| 126 | + PVRDMA_WC_WITH_SMAC = 1 << 4, | |
| 127 | + PVRDMA_WC_WITH_VLAN = 1 << 5, | |
| 128 | + PVRDMA_WC_FLAGS_MAX = PVRDMA_WC_WITH_VLAN, | |
| 129 | +}; | |
| 130 | + | |
| 131 | +struct pvrdma_alloc_ucontext_resp { | |
| 132 | + __u32 qp_tab_size; | |
| 133 | + __u32 reserved; | |
| 134 | +}; | |
| 135 | + | |
| 136 | +struct pvrdma_alloc_pd_resp { | |
| 137 | + __u32 pdn; | |
| 138 | + __u32 reserved; | |
| 139 | +}; | |
| 140 | + | |
| 141 | +struct pvrdma_create_cq { | |
| 142 | + __u64 buf_addr; | |
| 143 | + __u32 buf_size; | |
| 144 | + __u32 reserved; | |
| 145 | +}; | |
| 146 | + | |
| 147 | +struct pvrdma_create_cq_resp { | |
| 148 | + __u32 cqn; | |
| 149 | + __u32 reserved; | |
| 150 | +}; | |
| 151 | + | |
| 152 | +struct pvrdma_resize_cq { | |
| 153 | + __u64 buf_addr; | |
| 154 | + __u32 buf_size; | |
| 155 | + __u32 reserved; | |
| 156 | +}; | |
| 157 | + | |
| 158 | +struct pvrdma_create_srq { | |
| 159 | + __u64 buf_addr; | |
| 160 | +}; | |
| 161 | + | |
| 162 | +struct pvrdma_create_srq_resp { | |
| 163 | + __u32 srqn; | |
| 164 | + __u32 reserved; | |
| 165 | +}; | |
| 166 | + | |
| 167 | +struct pvrdma_create_qp { | |
| 168 | + __u64 rbuf_addr; | |
| 169 | + __u64 sbuf_addr; | |
| 170 | + __u32 rbuf_size; | |
| 171 | + __u32 sbuf_size; | |
| 172 | + __u64 qp_addr; | |
| 173 | +}; | |
| 174 | + | |
| 175 | +/* PVRDMA masked atomic compare and swap */ | |
| 176 | +struct pvrdma_ex_cmp_swap { | |
| 177 | + __u64 swap_val; | |
| 178 | + __u64 compare_val; | |
| 179 | + __u64 swap_mask; | |
| 180 | + __u64 compare_mask; | |
| 181 | +}; | |
| 182 | + | |
| 183 | +/* PVRDMA masked atomic fetch and add */ | |
| 184 | +struct pvrdma_ex_fetch_add { | |
| 185 | + __u64 add_val; | |
| 186 | + __u64 field_boundary; | |
| 187 | +}; | |
| 188 | + | |
| 189 | +/* PVRDMA address vector. */ | |
| 190 | +struct pvrdma_av { | |
| 191 | + __u32 port_pd; | |
| 192 | + __u32 sl_tclass_flowlabel; | |
| 193 | + __u8 dgid[16]; | |
| 194 | + __u8 src_path_bits; | |
| 195 | + __u8 gid_index; | |
| 196 | + __u8 stat_rate; | |
| 197 | + __u8 hop_limit; | |
| 198 | + __u8 dmac[6]; | |
| 199 | + __u8 reserved[6]; | |
| 200 | +}; | |
| 201 | + | |
| 202 | +/* PVRDMA scatter/gather entry */ | |
| 203 | +struct pvrdma_sge { | |
| 204 | + __u64 addr; | |
| 205 | + __u32 length; | |
| 206 | + __u32 lkey; | |
| 207 | +}; | |
| 208 | + | |
| 209 | +/* PVRDMA receive queue work request */ | |
| 210 | +struct pvrdma_rq_wqe_hdr { | |
| 211 | + __u64 wr_id; /* wr id */ | |
| 212 | + __u32 num_sge; /* size of s/g array */ | |
| 213 | + __u32 total_len; /* reserved */ | |
| 214 | +}; | |
| 215 | +/* Use pvrdma_sge (ib_sge) for receive queue s/g array elements. */ | |
| 216 | + | |
| 217 | +/* PVRDMA send queue work request */ | |
| 218 | +struct pvrdma_sq_wqe_hdr { | |
| 219 | + __u64 wr_id; /* wr id */ | |
| 220 | + __u32 num_sge; /* size of s/g array */ | |
| 221 | + __u32 total_len; /* reserved */ | |
| 222 | + __u32 opcode; /* operation type */ | |
| 223 | + __u32 send_flags; /* wr flags */ | |
| 224 | + union { | |
| 225 | + __u32 imm_data; | |
| 226 | + __u32 invalidate_rkey; | |
| 227 | + } ex; | |
| 228 | + __u32 reserved; | |
| 229 | + union { | |
| 230 | + struct { | |
| 231 | + __u64 remote_addr; | |
| 232 | + __u32 rkey; | |
| 233 | + __u8 reserved[4]; | |
| 234 | + } rdma; | |
| 235 | + struct { | |
| 236 | + __u64 remote_addr; | |
| 237 | + __u64 compare_add; | |
| 238 | + __u64 swap; | |
| 239 | + __u32 rkey; | |
| 240 | + __u32 reserved; | |
| 241 | + } atomic; | |
| 242 | + struct { | |
| 243 | + __u64 remote_addr; | |
| 244 | + __u32 log_arg_sz; | |
| 245 | + __u32 rkey; | |
| 246 | + union { | |
| 247 | + struct pvrdma_ex_cmp_swap cmp_swap; | |
| 248 | + struct pvrdma_ex_fetch_add fetch_add; | |
| 249 | + } wr_data; | |
| 250 | + } masked_atomics; | |
| 251 | + struct { | |
| 252 | + __u64 iova_start; | |
| 253 | + __u64 pl_pdir_dma; | |
| 254 | + __u32 page_shift; | |
| 255 | + __u32 page_list_len; | |
| 256 | + __u32 length; | |
| 257 | + __u32 access_flags; | |
| 258 | + __u32 rkey; | |
| 259 | + } fast_reg; | |
| 260 | + struct { | |
| 261 | + __u32 remote_qpn; | |
| 262 | + __u32 remote_qkey; | |
| 263 | + struct pvrdma_av av; | |
| 264 | + } ud; | |
| 265 | + } wr; | |
| 266 | +}; | |
| 267 | +/* Use pvrdma_sge (ib_sge) for send queue s/g array elements. */ | |
| 268 | + | |
| 269 | +/* Completion queue element. */ | |
| 270 | +struct pvrdma_cqe { | |
| 271 | + __u64 wr_id; | |
| 272 | + __u64 qp; | |
| 273 | + __u32 opcode; | |
| 274 | + __u32 status; | |
| 275 | + __u32 byte_len; | |
| 276 | + __u32 imm_data; | |
| 277 | + __u32 src_qp; | |
| 278 | + __u32 wc_flags; | |
| 279 | + __u32 vendor_err; | |
| 280 | + __u16 pkey_index; | |
| 281 | + __u16 slid; | |
| 282 | + __u8 sl; | |
| 283 | + __u8 dlid_path_bits; | |
| 284 | + __u8 port_num; | |
| 285 | + __u8 smac[6]; | |
| 286 | + __u8 reserved2[7]; /* Pad to next power of 2 (64). */ | |
| 287 | +}; | |
| 288 | + | |
| 289 | +#endif /* __VMW_PVRDMA_ABI_H__ */ | |