]>
Commit | Line | Data |
---|---|---|
919ae3dd YS |
1 | /* |
2 | * QEMU paravirtual RDMA | |
3 | * | |
4 | * Copyright (C) 2018 Oracle | |
5 | * Copyright (C) 2018 Red Hat Inc | |
6 | * | |
7 | * Authors: | |
8 | * Yuval Shaia <yuval.shaia@oracle.com> | |
9 | * Marcel Apfelbaum <marcel@redhat.com> | |
10 | * | |
11 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
12 | * See the COPYING file in the top-level directory. | |
13 | * | |
14 | */ | |
15 | ||
0efc9511 MT |
16 | #include "qemu/osdep.h" |
17 | #include "qapi/error.h" | |
18 | #include "hw/hw.h" | |
19 | #include "hw/pci/pci.h" | |
20 | #include "hw/pci/pci_ids.h" | |
21 | #include "hw/pci/msi.h" | |
22 | #include "hw/pci/msix.h" | |
23 | #include "hw/qdev-core.h" | |
24 | #include "hw/qdev-properties.h" | |
25 | #include "cpu.h" | |
919ae3dd YS |
26 | #include "trace.h" |
27 | ||
28 | #include "../rdma_rm.h" | |
29 | #include "../rdma_backend.h" | |
30 | #include "../rdma_utils.h" | |
31 | ||
32 | #include <infiniband/verbs.h> | |
33 | #include "pvrdma.h" | |
0efc9511 MT |
34 | #include "standard-headers/rdma/vmw_pvrdma-abi.h" |
35 | #include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" | |
919ae3dd YS |
36 | #include "pvrdma_qp_ops.h" |
37 | ||
38 | static Property pvrdma_dev_properties[] = { | |
39 | DEFINE_PROP_STRING("backend-dev", PVRDMADev, backend_device_name), | |
40 | DEFINE_PROP_UINT8("backend-port", PVRDMADev, backend_port_num, 1), | |
41 | DEFINE_PROP_UINT8("backend-gid-idx", PVRDMADev, backend_gid_idx, 0), | |
42 | DEFINE_PROP_UINT64("dev-caps-max-mr-size", PVRDMADev, dev_attr.max_mr_size, | |
43 | MAX_MR_SIZE), | |
44 | DEFINE_PROP_INT32("dev-caps-max-qp", PVRDMADev, dev_attr.max_qp, MAX_QP), | |
45 | DEFINE_PROP_INT32("dev-caps-max-sge", PVRDMADev, dev_attr.max_sge, MAX_SGE), | |
46 | DEFINE_PROP_INT32("dev-caps-max-cq", PVRDMADev, dev_attr.max_cq, MAX_CQ), | |
47 | DEFINE_PROP_INT32("dev-caps-max-mr", PVRDMADev, dev_attr.max_mr, MAX_MR), | |
48 | DEFINE_PROP_INT32("dev-caps-max-pd", PVRDMADev, dev_attr.max_pd, MAX_PD), | |
49 | DEFINE_PROP_INT32("dev-caps-qp-rd-atom", PVRDMADev, dev_attr.max_qp_rd_atom, | |
50 | MAX_QP_RD_ATOM), | |
51 | DEFINE_PROP_INT32("dev-caps-max-qp-init-rd-atom", PVRDMADev, | |
52 | dev_attr.max_qp_init_rd_atom, MAX_QP_INIT_RD_ATOM), | |
53 | DEFINE_PROP_INT32("dev-caps-max-ah", PVRDMADev, dev_attr.max_ah, MAX_AH), | |
605ec166 | 54 | DEFINE_PROP_CHR("mad-chardev", PVRDMADev, mad_chr), |
919ae3dd YS |
55 | DEFINE_PROP_END_OF_LIST(), |
56 | }; | |
57 | ||
58 | static void free_dev_ring(PCIDevice *pci_dev, PvrdmaRing *ring, | |
59 | void *ring_state) | |
60 | { | |
61 | pvrdma_ring_free(ring); | |
62 | rdma_pci_dma_unmap(pci_dev, ring_state, TARGET_PAGE_SIZE); | |
63 | } | |
64 | ||
65 | static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state, | |
66 | const char *name, PCIDevice *pci_dev, | |
67 | dma_addr_t dir_addr, uint32_t num_pages) | |
68 | { | |
69 | uint64_t *dir, *tbl; | |
70 | int rc = 0; | |
71 | ||
72 | pr_dbg("Initializing device ring %s\n", name); | |
73 | pr_dbg("pdir_dma=0x%llx\n", (long long unsigned int)dir_addr); | |
74 | pr_dbg("num_pages=%d\n", num_pages); | |
75 | dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE); | |
76 | if (!dir) { | |
77 | pr_err("Failed to map to page directory\n"); | |
78 | rc = -ENOMEM; | |
79 | goto out; | |
80 | } | |
81 | tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE); | |
82 | if (!tbl) { | |
83 | pr_err("Failed to map to page table\n"); | |
84 | rc = -ENOMEM; | |
85 | goto out_free_dir; | |
86 | } | |
87 | ||
88 | *ring_state = rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); | |
89 | if (!*ring_state) { | |
90 | pr_err("Failed to map to ring state\n"); | |
91 | rc = -ENOMEM; | |
92 | goto out_free_tbl; | |
93 | } | |
94 | /* RX ring is the second */ | |
197053e2 | 95 | (*ring_state)++; |
919ae3dd YS |
96 | rc = pvrdma_ring_init(ring, name, pci_dev, |
97 | (struct pvrdma_ring *)*ring_state, | |
98 | (num_pages - 1) * TARGET_PAGE_SIZE / | |
99 | sizeof(struct pvrdma_cqne), | |
100 | sizeof(struct pvrdma_cqne), | |
101 | (dma_addr_t *)&tbl[1], (dma_addr_t)num_pages - 1); | |
102 | if (rc) { | |
103 | pr_err("Failed to initialize ring\n"); | |
104 | rc = -ENOMEM; | |
105 | goto out_free_ring_state; | |
106 | } | |
107 | ||
108 | goto out_free_tbl; | |
109 | ||
110 | out_free_ring_state: | |
111 | rdma_pci_dma_unmap(pci_dev, *ring_state, TARGET_PAGE_SIZE); | |
112 | ||
113 | out_free_tbl: | |
114 | rdma_pci_dma_unmap(pci_dev, tbl, TARGET_PAGE_SIZE); | |
115 | ||
116 | out_free_dir: | |
117 | rdma_pci_dma_unmap(pci_dev, dir, TARGET_PAGE_SIZE); | |
118 | ||
119 | out: | |
120 | return rc; | |
121 | } | |
122 | ||
123 | static void free_dsr(PVRDMADev *dev) | |
124 | { | |
125 | PCIDevice *pci_dev = PCI_DEVICE(dev); | |
126 | ||
127 | if (!dev->dsr_info.dsr) { | |
128 | return; | |
129 | } | |
130 | ||
131 | free_dev_ring(pci_dev, &dev->dsr_info.async, | |
132 | dev->dsr_info.async_ring_state); | |
133 | ||
134 | free_dev_ring(pci_dev, &dev->dsr_info.cq, dev->dsr_info.cq_ring_state); | |
135 | ||
136 | rdma_pci_dma_unmap(pci_dev, dev->dsr_info.req, | |
137 | sizeof(union pvrdma_cmd_req)); | |
138 | ||
139 | rdma_pci_dma_unmap(pci_dev, dev->dsr_info.rsp, | |
140 | sizeof(union pvrdma_cmd_resp)); | |
141 | ||
142 | rdma_pci_dma_unmap(pci_dev, dev->dsr_info.dsr, | |
143 | sizeof(struct pvrdma_device_shared_region)); | |
144 | ||
145 | dev->dsr_info.dsr = NULL; | |
146 | } | |
147 | ||
148 | static int load_dsr(PVRDMADev *dev) | |
149 | { | |
150 | int rc = 0; | |
151 | PCIDevice *pci_dev = PCI_DEVICE(dev); | |
152 | DSRInfo *dsr_info; | |
153 | struct pvrdma_device_shared_region *dsr; | |
154 | ||
155 | free_dsr(dev); | |
156 | ||
157 | /* Map to DSR */ | |
158 | pr_dbg("dsr_dma=0x%llx\n", (long long unsigned int)dev->dsr_info.dma); | |
159 | dev->dsr_info.dsr = rdma_pci_dma_map(pci_dev, dev->dsr_info.dma, | |
160 | sizeof(struct pvrdma_device_shared_region)); | |
161 | if (!dev->dsr_info.dsr) { | |
162 | pr_err("Failed to map to DSR\n"); | |
163 | rc = -ENOMEM; | |
164 | goto out; | |
165 | } | |
166 | ||
167 | /* Shortcuts */ | |
168 | dsr_info = &dev->dsr_info; | |
169 | dsr = dsr_info->dsr; | |
170 | ||
171 | /* Map to command slot */ | |
172 | pr_dbg("cmd_dma=0x%llx\n", (long long unsigned int)dsr->cmd_slot_dma); | |
173 | dsr_info->req = rdma_pci_dma_map(pci_dev, dsr->cmd_slot_dma, | |
174 | sizeof(union pvrdma_cmd_req)); | |
175 | if (!dsr_info->req) { | |
176 | pr_err("Failed to map to command slot address\n"); | |
177 | rc = -ENOMEM; | |
178 | goto out_free_dsr; | |
179 | } | |
180 | ||
181 | /* Map to response slot */ | |
182 | pr_dbg("rsp_dma=0x%llx\n", (long long unsigned int)dsr->resp_slot_dma); | |
183 | dsr_info->rsp = rdma_pci_dma_map(pci_dev, dsr->resp_slot_dma, | |
184 | sizeof(union pvrdma_cmd_resp)); | |
185 | if (!dsr_info->rsp) { | |
186 | pr_err("Failed to map to response slot address\n"); | |
187 | rc = -ENOMEM; | |
188 | goto out_free_req; | |
189 | } | |
190 | ||
191 | /* Map to CQ notification ring */ | |
192 | rc = init_dev_ring(&dsr_info->cq, &dsr_info->cq_ring_state, "dev_cq", | |
193 | pci_dev, dsr->cq_ring_pages.pdir_dma, | |
194 | dsr->cq_ring_pages.num_pages); | |
195 | if (rc) { | |
196 | pr_err("Failed to map to initialize CQ ring\n"); | |
197 | rc = -ENOMEM; | |
198 | goto out_free_rsp; | |
199 | } | |
200 | ||
201 | /* Map to event notification ring */ | |
202 | rc = init_dev_ring(&dsr_info->async, &dsr_info->async_ring_state, | |
203 | "dev_async", pci_dev, dsr->async_ring_pages.pdir_dma, | |
204 | dsr->async_ring_pages.num_pages); | |
205 | if (rc) { | |
206 | pr_err("Failed to map to initialize event ring\n"); | |
207 | rc = -ENOMEM; | |
208 | goto out_free_rsp; | |
209 | } | |
210 | ||
211 | goto out; | |
212 | ||
213 | out_free_rsp: | |
214 | rdma_pci_dma_unmap(pci_dev, dsr_info->rsp, sizeof(union pvrdma_cmd_resp)); | |
215 | ||
216 | out_free_req: | |
217 | rdma_pci_dma_unmap(pci_dev, dsr_info->req, sizeof(union pvrdma_cmd_req)); | |
218 | ||
219 | out_free_dsr: | |
220 | rdma_pci_dma_unmap(pci_dev, dsr_info->dsr, | |
221 | sizeof(struct pvrdma_device_shared_region)); | |
222 | dsr_info->dsr = NULL; | |
223 | ||
224 | out: | |
225 | return rc; | |
226 | } | |
227 | ||
228 | static void init_dsr_dev_caps(PVRDMADev *dev) | |
229 | { | |
230 | struct pvrdma_device_shared_region *dsr; | |
231 | ||
232 | if (dev->dsr_info.dsr == NULL) { | |
233 | pr_err("Can't initialized DSR\n"); | |
234 | return; | |
235 | } | |
236 | ||
237 | dsr = dev->dsr_info.dsr; | |
238 | ||
239 | dsr->caps.fw_ver = PVRDMA_FW_VERSION; | |
6f559013 | 240 | pr_dbg("fw_ver=0x%" PRIx64 "\n", dsr->caps.fw_ver); |
919ae3dd YS |
241 | |
242 | dsr->caps.mode = PVRDMA_DEVICE_MODE_ROCE; | |
243 | pr_dbg("mode=%d\n", dsr->caps.mode); | |
244 | ||
245 | dsr->caps.gid_types |= PVRDMA_GID_TYPE_FLAG_ROCE_V1; | |
246 | pr_dbg("gid_types=0x%x\n", dsr->caps.gid_types); | |
247 | ||
248 | dsr->caps.max_uar = RDMA_BAR2_UAR_SIZE; | |
249 | pr_dbg("max_uar=%d\n", dsr->caps.max_uar); | |
250 | ||
251 | dsr->caps.max_mr_size = dev->dev_attr.max_mr_size; | |
252 | dsr->caps.max_qp = dev->dev_attr.max_qp; | |
253 | dsr->caps.max_qp_wr = dev->dev_attr.max_qp_wr; | |
254 | dsr->caps.max_sge = dev->dev_attr.max_sge; | |
255 | dsr->caps.max_cq = dev->dev_attr.max_cq; | |
256 | dsr->caps.max_cqe = dev->dev_attr.max_cqe; | |
257 | dsr->caps.max_mr = dev->dev_attr.max_mr; | |
258 | dsr->caps.max_pd = dev->dev_attr.max_pd; | |
259 | dsr->caps.max_ah = dev->dev_attr.max_ah; | |
260 | ||
261 | dsr->caps.gid_tbl_len = MAX_GIDS; | |
262 | pr_dbg("gid_tbl_len=%d\n", dsr->caps.gid_tbl_len); | |
263 | ||
264 | dsr->caps.sys_image_guid = 0; | |
6f559013 | 265 | pr_dbg("sys_image_guid=%" PRIx64 "\n", dsr->caps.sys_image_guid); |
919ae3dd YS |
266 | |
267 | dsr->caps.node_guid = cpu_to_be64(dev->node_guid); | |
6f559013 | 268 | pr_dbg("node_guid=%" PRIx64 "\n", be64_to_cpu(dsr->caps.node_guid)); |
919ae3dd YS |
269 | |
270 | dsr->caps.phys_port_cnt = MAX_PORTS; | |
271 | pr_dbg("phys_port_cnt=%d\n", dsr->caps.phys_port_cnt); | |
272 | ||
273 | dsr->caps.max_pkeys = MAX_PKEYS; | |
274 | pr_dbg("max_pkeys=%d\n", dsr->caps.max_pkeys); | |
275 | ||
276 | pr_dbg("Initialized\n"); | |
277 | } | |
278 | ||
919ae3dd YS |
279 | static void init_ports(PVRDMADev *dev, Error **errp) |
280 | { | |
281 | int i; | |
282 | ||
283 | memset(dev->rdma_dev_res.ports, 0, sizeof(dev->rdma_dev_res.ports)); | |
284 | ||
285 | for (i = 0; i < MAX_PORTS; i++) { | |
197053e2 | 286 | dev->rdma_dev_res.ports[i].state = IBV_PORT_DOWN; |
919ae3dd YS |
287 | } |
288 | } | |
289 | ||
75152227 YS |
290 | static void uninit_msix(PCIDevice *pdev, int used_vectors) |
291 | { | |
292 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
293 | int i; | |
294 | ||
295 | for (i = 0; i < used_vectors; i++) { | |
296 | msix_vector_unuse(pdev, i); | |
297 | } | |
298 | ||
299 | msix_uninit(pdev, &dev->msix, &dev->msix); | |
300 | } | |
301 | ||
302 | static int init_msix(PCIDevice *pdev, Error **errp) | |
303 | { | |
304 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
305 | int i; | |
306 | int rc; | |
307 | ||
308 | rc = msix_init(pdev, RDMA_MAX_INTRS, &dev->msix, RDMA_MSIX_BAR_IDX, | |
309 | RDMA_MSIX_TABLE, &dev->msix, RDMA_MSIX_BAR_IDX, | |
310 | RDMA_MSIX_PBA, 0, NULL); | |
311 | ||
312 | if (rc < 0) { | |
313 | error_setg(errp, "Failed to initialize MSI-X"); | |
314 | return rc; | |
315 | } | |
316 | ||
317 | for (i = 0; i < RDMA_MAX_INTRS; i++) { | |
318 | rc = msix_vector_use(PCI_DEVICE(dev), i); | |
319 | if (rc < 0) { | |
320 | error_setg(errp, "Fail mark MSI-X vector %d", i); | |
321 | uninit_msix(pdev, i); | |
322 | return rc; | |
323 | } | |
324 | } | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | static void pvrdma_fini(PCIDevice *pdev) | |
330 | { | |
331 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
332 | ||
333 | pr_dbg("Closing device %s %x.%x\n", pdev->name, PCI_SLOT(pdev->devfn), | |
334 | PCI_FUNC(pdev->devfn)); | |
335 | ||
336 | pvrdma_qp_ops_fini(); | |
337 | ||
338 | rdma_rm_fini(&dev->rdma_dev_res); | |
339 | ||
340 | rdma_backend_fini(&dev->backend_dev); | |
341 | ||
342 | free_dsr(dev); | |
343 | ||
344 | if (msix_enabled(pdev)) { | |
345 | uninit_msix(pdev, RDMA_MAX_INTRS); | |
346 | } | |
347 | } | |
348 | ||
349 | static void pvrdma_stop(PVRDMADev *dev) | |
350 | { | |
351 | rdma_backend_stop(&dev->backend_dev); | |
352 | } | |
353 | ||
354 | static void pvrdma_start(PVRDMADev *dev) | |
355 | { | |
356 | rdma_backend_start(&dev->backend_dev); | |
357 | } | |
358 | ||
919ae3dd YS |
359 | static void activate_device(PVRDMADev *dev) |
360 | { | |
75152227 | 361 | pvrdma_start(dev); |
919ae3dd YS |
362 | set_reg_val(dev, PVRDMA_REG_ERR, 0); |
363 | pr_dbg("Device activated\n"); | |
364 | } | |
365 | ||
366 | static int unquiesce_device(PVRDMADev *dev) | |
367 | { | |
368 | pr_dbg("Device unquiesced\n"); | |
369 | return 0; | |
370 | } | |
371 | ||
f00c48ca | 372 | static void reset_device(PVRDMADev *dev) |
919ae3dd | 373 | { |
75152227 YS |
374 | pvrdma_stop(dev); |
375 | ||
919ae3dd | 376 | pr_dbg("Device reset complete\n"); |
919ae3dd YS |
377 | } |
378 | ||
379 | static uint64_t regs_read(void *opaque, hwaddr addr, unsigned size) | |
380 | { | |
381 | PVRDMADev *dev = opaque; | |
382 | uint32_t val; | |
383 | ||
384 | /* pr_dbg("addr=0x%lx, size=%d\n", addr, size); */ | |
385 | ||
386 | if (get_reg_val(dev, addr, &val)) { | |
387 | pr_dbg("Error trying to read REG value from address 0x%x\n", | |
388 | (uint32_t)addr); | |
389 | return -EINVAL; | |
390 | } | |
391 | ||
392 | trace_pvrdma_regs_read(addr, val); | |
393 | ||
394 | return val; | |
395 | } | |
396 | ||
397 | static void regs_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
398 | { | |
399 | PVRDMADev *dev = opaque; | |
400 | ||
401 | /* pr_dbg("addr=0x%lx, val=0x%x, size=%d\n", addr, (uint32_t)val, size); */ | |
402 | ||
403 | if (set_reg_val(dev, addr, val)) { | |
6f559013 YS |
404 | pr_err("Fail to set REG value, addr=0x%" PRIx64 ", val=0x%" PRIx64 "\n", |
405 | addr, val); | |
919ae3dd YS |
406 | return; |
407 | } | |
408 | ||
409 | trace_pvrdma_regs_write(addr, val); | |
410 | ||
411 | switch (addr) { | |
412 | case PVRDMA_REG_DSRLOW: | |
413 | dev->dsr_info.dma = val; | |
414 | break; | |
415 | case PVRDMA_REG_DSRHIGH: | |
416 | dev->dsr_info.dma |= val << 32; | |
417 | load_dsr(dev); | |
418 | init_dsr_dev_caps(dev); | |
419 | break; | |
420 | case PVRDMA_REG_CTL: | |
421 | switch (val) { | |
422 | case PVRDMA_DEVICE_CTL_ACTIVATE: | |
423 | activate_device(dev); | |
424 | break; | |
425 | case PVRDMA_DEVICE_CTL_UNQUIESCE: | |
426 | unquiesce_device(dev); | |
427 | break; | |
428 | case PVRDMA_DEVICE_CTL_RESET: | |
429 | reset_device(dev); | |
430 | break; | |
431 | } | |
67b32fe2 | 432 | break; |
919ae3dd | 433 | case PVRDMA_REG_IMR: |
6f559013 | 434 | pr_dbg("Interrupt mask=0x%" PRIx64 "\n", val); |
919ae3dd YS |
435 | dev->interrupt_mask = val; |
436 | break; | |
437 | case PVRDMA_REG_REQUEST: | |
438 | if (val == 0) { | |
439 | execute_command(dev); | |
440 | } | |
67b32fe2 | 441 | break; |
919ae3dd YS |
442 | default: |
443 | break; | |
444 | } | |
445 | } | |
446 | ||
447 | static const MemoryRegionOps regs_ops = { | |
448 | .read = regs_read, | |
449 | .write = regs_write, | |
450 | .endianness = DEVICE_LITTLE_ENDIAN, | |
451 | .impl = { | |
452 | .min_access_size = sizeof(uint32_t), | |
453 | .max_access_size = sizeof(uint32_t), | |
454 | }, | |
455 | }; | |
456 | ||
457 | static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
458 | { | |
459 | PVRDMADev *dev = opaque; | |
460 | ||
461 | /* pr_dbg("addr=0x%lx, val=0x%x, size=%d\n", addr, (uint32_t)val, size); */ | |
462 | ||
463 | switch (addr & 0xFFF) { /* Mask with 0xFFF as each UC gets page */ | |
464 | case PVRDMA_UAR_QP_OFFSET: | |
6f559013 YS |
465 | pr_dbg("UAR QP command, addr=0x%" PRIx64 ", val=0x%" PRIx64 "\n", |
466 | (uint64_t)addr, val); | |
919ae3dd YS |
467 | if (val & PVRDMA_UAR_QP_SEND) { |
468 | pvrdma_qp_send(dev, val & PVRDMA_UAR_HANDLE_MASK); | |
469 | } | |
470 | if (val & PVRDMA_UAR_QP_RECV) { | |
471 | pvrdma_qp_recv(dev, val & PVRDMA_UAR_HANDLE_MASK); | |
472 | } | |
473 | break; | |
474 | case PVRDMA_UAR_CQ_OFFSET: | |
475 | /* pr_dbg("UAR CQ cmd, addr=0x%x, val=0x%lx\n", (uint32_t)addr, val); */ | |
476 | if (val & PVRDMA_UAR_CQ_ARM) { | |
477 | rdma_rm_req_notify_cq(&dev->rdma_dev_res, | |
478 | val & PVRDMA_UAR_HANDLE_MASK, | |
479 | !!(val & PVRDMA_UAR_CQ_ARM_SOL)); | |
480 | } | |
481 | if (val & PVRDMA_UAR_CQ_ARM_SOL) { | |
6f559013 YS |
482 | pr_dbg("UAR_CQ_ARM_SOL (%" PRIx64 ")\n", |
483 | val & PVRDMA_UAR_HANDLE_MASK); | |
919ae3dd YS |
484 | } |
485 | if (val & PVRDMA_UAR_CQ_POLL) { | |
6f559013 | 486 | pr_dbg("UAR_CQ_POLL (%" PRIx64 ")\n", val & PVRDMA_UAR_HANDLE_MASK); |
919ae3dd YS |
487 | pvrdma_cq_poll(&dev->rdma_dev_res, val & PVRDMA_UAR_HANDLE_MASK); |
488 | } | |
489 | break; | |
490 | default: | |
6f559013 YS |
491 | pr_err("Unsupported command, addr=0x%" PRIx64 ", val=0x%" PRIx64 "\n", |
492 | addr, val); | |
919ae3dd YS |
493 | break; |
494 | } | |
495 | } | |
496 | ||
497 | static const MemoryRegionOps uar_ops = { | |
498 | .write = uar_write, | |
499 | .endianness = DEVICE_LITTLE_ENDIAN, | |
500 | .impl = { | |
501 | .min_access_size = sizeof(uint32_t), | |
502 | .max_access_size = sizeof(uint32_t), | |
503 | }, | |
504 | }; | |
505 | ||
506 | static void init_pci_config(PCIDevice *pdev) | |
507 | { | |
508 | pdev->config[PCI_INTERRUPT_PIN] = 1; | |
509 | } | |
510 | ||
511 | static void init_bars(PCIDevice *pdev) | |
512 | { | |
513 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
514 | ||
515 | /* BAR 0 - MSI-X */ | |
516 | memory_region_init(&dev->msix, OBJECT(dev), "pvrdma-msix", | |
517 | RDMA_BAR0_MSIX_SIZE); | |
518 | pci_register_bar(pdev, RDMA_MSIX_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, | |
519 | &dev->msix); | |
520 | ||
521 | /* BAR 1 - Registers */ | |
522 | memset(&dev->regs_data, 0, sizeof(dev->regs_data)); | |
523 | memory_region_init_io(&dev->regs, OBJECT(dev), ®s_ops, dev, | |
35092917 | 524 | "pvrdma-regs", sizeof(dev->regs_data)); |
919ae3dd YS |
525 | pci_register_bar(pdev, RDMA_REG_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, |
526 | &dev->regs); | |
527 | ||
528 | /* BAR 2 - UAR */ | |
529 | memset(&dev->uar_data, 0, sizeof(dev->uar_data)); | |
530 | memory_region_init_io(&dev->uar, OBJECT(dev), &uar_ops, dev, "rdma-uar", | |
35092917 | 531 | sizeof(dev->uar_data)); |
919ae3dd YS |
532 | pci_register_bar(pdev, RDMA_UAR_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, |
533 | &dev->uar); | |
534 | } | |
535 | ||
536 | static void init_regs(PCIDevice *pdev) | |
537 | { | |
538 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
539 | ||
540 | set_reg_val(dev, PVRDMA_REG_VERSION, PVRDMA_HW_VERSION); | |
541 | set_reg_val(dev, PVRDMA_REG_ERR, 0xFFFF); | |
542 | } | |
543 | ||
919ae3dd YS |
544 | static void init_dev_caps(PVRDMADev *dev) |
545 | { | |
546 | size_t pg_tbl_bytes = TARGET_PAGE_SIZE * | |
547 | (TARGET_PAGE_SIZE / sizeof(uint64_t)); | |
548 | size_t wr_sz = MAX(sizeof(struct pvrdma_sq_wqe_hdr), | |
549 | sizeof(struct pvrdma_rq_wqe_hdr)); | |
550 | ||
551 | dev->dev_attr.max_qp_wr = pg_tbl_bytes / | |
552 | (wr_sz + sizeof(struct pvrdma_sge) * MAX_SGE) - | |
553 | TARGET_PAGE_SIZE; /* First page is ring state */ | |
554 | pr_dbg("max_qp_wr=%d\n", dev->dev_attr.max_qp_wr); | |
555 | ||
556 | dev->dev_attr.max_cqe = pg_tbl_bytes / sizeof(struct pvrdma_cqe) - | |
557 | TARGET_PAGE_SIZE; /* First page is ring state */ | |
558 | pr_dbg("max_cqe=%d\n", dev->dev_attr.max_cqe); | |
559 | } | |
560 | ||
561 | static int pvrdma_check_ram_shared(Object *obj, void *opaque) | |
562 | { | |
563 | bool *shared = opaque; | |
564 | ||
565 | if (object_dynamic_cast(obj, "memory-backend-ram")) { | |
566 | *shared = object_property_get_bool(obj, "share", NULL); | |
567 | } | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | static void pvrdma_realize(PCIDevice *pdev, Error **errp) | |
573 | { | |
574 | int rc; | |
575 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
576 | Object *memdev_root; | |
577 | bool ram_shared = false; | |
578 | ||
ef846e02 YS |
579 | init_pr_dbg(); |
580 | ||
919ae3dd YS |
581 | pr_dbg("Initializing device %s %x.%x\n", pdev->name, |
582 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | |
583 | ||
584 | if (TARGET_PAGE_SIZE != getpagesize()) { | |
585 | error_setg(errp, "Target page size must be the same as host page size"); | |
586 | return; | |
587 | } | |
588 | ||
589 | memdev_root = object_resolve_path("/objects", NULL); | |
590 | if (memdev_root) { | |
591 | object_child_foreach(memdev_root, pvrdma_check_ram_shared, &ram_shared); | |
592 | } | |
593 | if (!ram_shared) { | |
594 | error_setg(errp, "Only shared memory backed ram is supported"); | |
595 | return; | |
596 | } | |
597 | ||
598 | dev->dsr_info.dsr = NULL; | |
599 | ||
600 | init_pci_config(pdev); | |
601 | ||
602 | init_bars(pdev); | |
603 | ||
604 | init_regs(pdev); | |
605 | ||
606 | init_dev_caps(dev); | |
607 | ||
608 | rc = init_msix(pdev, errp); | |
609 | if (rc) { | |
610 | goto out; | |
611 | } | |
612 | ||
430e440c | 613 | rc = rdma_backend_init(&dev->backend_dev, pdev, &dev->rdma_dev_res, |
919ae3dd | 614 | dev->backend_device_name, dev->backend_port_num, |
605ec166 YS |
615 | dev->backend_gid_idx, &dev->dev_attr, &dev->mad_chr, |
616 | errp); | |
919ae3dd YS |
617 | if (rc) { |
618 | goto out; | |
619 | } | |
620 | ||
621 | rc = rdma_rm_init(&dev->rdma_dev_res, &dev->dev_attr, errp); | |
622 | if (rc) { | |
623 | goto out; | |
624 | } | |
625 | ||
626 | init_ports(dev, errp); | |
627 | ||
628 | rc = pvrdma_qp_ops_init(); | |
629 | if (rc) { | |
630 | goto out; | |
631 | } | |
632 | ||
633 | out: | |
634 | if (rc) { | |
635 | error_append_hint(errp, "Device fail to load\n"); | |
636 | } | |
637 | } | |
638 | ||
639 | static void pvrdma_exit(PCIDevice *pdev) | |
640 | { | |
75152227 | 641 | pvrdma_fini(pdev); |
919ae3dd YS |
642 | } |
643 | ||
644 | static void pvrdma_class_init(ObjectClass *klass, void *data) | |
645 | { | |
646 | DeviceClass *dc = DEVICE_CLASS(klass); | |
647 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
648 | ||
649 | k->realize = pvrdma_realize; | |
650 | k->exit = pvrdma_exit; | |
651 | k->vendor_id = PCI_VENDOR_ID_VMWARE; | |
652 | k->device_id = PCI_DEVICE_ID_VMWARE_PVRDMA; | |
653 | k->revision = 0x00; | |
654 | k->class_id = PCI_CLASS_NETWORK_OTHER; | |
655 | ||
656 | dc->desc = "RDMA Device"; | |
657 | dc->props = pvrdma_dev_properties; | |
658 | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); | |
659 | } | |
660 | ||
661 | static const TypeInfo pvrdma_info = { | |
662 | .name = PVRDMA_HW_NAME, | |
663 | .parent = TYPE_PCI_DEVICE, | |
664 | .instance_size = sizeof(PVRDMADev), | |
665 | .class_init = pvrdma_class_init, | |
666 | .interfaces = (InterfaceInfo[]) { | |
667 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
668 | { } | |
669 | } | |
670 | }; | |
671 | ||
672 | static void register_types(void) | |
673 | { | |
674 | type_register_static(&pvrdma_info); | |
675 | } | |
676 | ||
677 | type_init(register_types) |