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