]>
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 | ||
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> | |
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" | |
34 | #include <standard-headers/rdma/vmw_pvrdma-abi.h> | |
35 | #include <standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h> | |
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 */ | |
94 | (struct pvrdma_ring *)(*ring_state)++; | |
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; | |
239 | pr_dbg("fw_ver=0x%lx\n", dsr->caps.fw_ver); | |
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; | |
264 | pr_dbg("sys_image_guid=%lx\n", dsr->caps.sys_image_guid); | |
265 | ||
266 | dsr->caps.node_guid = cpu_to_be64(dev->node_guid); | |
267 | pr_dbg("node_guid=%llx\n", | |
268 | (long long unsigned int)be64_to_cpu(dsr->caps.node_guid)); | |
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 | ||
279 | static void free_ports(PVRDMADev *dev) | |
280 | { | |
281 | int i; | |
282 | ||
283 | for (i = 0; i < MAX_PORTS; i++) { | |
284 | g_free(dev->rdma_dev_res.ports[i].gid_tbl); | |
285 | } | |
286 | } | |
287 | ||
288 | static void init_ports(PVRDMADev *dev, Error **errp) | |
289 | { | |
290 | int i; | |
291 | ||
292 | memset(dev->rdma_dev_res.ports, 0, sizeof(dev->rdma_dev_res.ports)); | |
293 | ||
294 | for (i = 0; i < MAX_PORTS; i++) { | |
295 | dev->rdma_dev_res.ports[i].state = PVRDMA_PORT_DOWN; | |
296 | ||
297 | dev->rdma_dev_res.ports[i].pkey_tbl = | |
298 | g_malloc0(sizeof(*dev->rdma_dev_res.ports[i].pkey_tbl) * | |
299 | MAX_PORT_PKEYS); | |
300 | } | |
301 | } | |
302 | ||
303 | static void activate_device(PVRDMADev *dev) | |
304 | { | |
305 | set_reg_val(dev, PVRDMA_REG_ERR, 0); | |
306 | pr_dbg("Device activated\n"); | |
307 | } | |
308 | ||
309 | static int unquiesce_device(PVRDMADev *dev) | |
310 | { | |
311 | pr_dbg("Device unquiesced\n"); | |
312 | return 0; | |
313 | } | |
314 | ||
315 | static int reset_device(PVRDMADev *dev) | |
316 | { | |
317 | pr_dbg("Device reset complete\n"); | |
318 | return 0; | |
319 | } | |
320 | ||
321 | static uint64_t regs_read(void *opaque, hwaddr addr, unsigned size) | |
322 | { | |
323 | PVRDMADev *dev = opaque; | |
324 | uint32_t val; | |
325 | ||
326 | /* pr_dbg("addr=0x%lx, size=%d\n", addr, size); */ | |
327 | ||
328 | if (get_reg_val(dev, addr, &val)) { | |
329 | pr_dbg("Error trying to read REG value from address 0x%x\n", | |
330 | (uint32_t)addr); | |
331 | return -EINVAL; | |
332 | } | |
333 | ||
334 | trace_pvrdma_regs_read(addr, val); | |
335 | ||
336 | return val; | |
337 | } | |
338 | ||
339 | static void regs_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
340 | { | |
341 | PVRDMADev *dev = opaque; | |
342 | ||
343 | /* pr_dbg("addr=0x%lx, val=0x%x, size=%d\n", addr, (uint32_t)val, size); */ | |
344 | ||
345 | if (set_reg_val(dev, addr, val)) { | |
346 | pr_err("Error trying to set REG value, addr=0x%lx, val=0x%lx\n", | |
347 | (uint64_t)addr, val); | |
348 | return; | |
349 | } | |
350 | ||
351 | trace_pvrdma_regs_write(addr, val); | |
352 | ||
353 | switch (addr) { | |
354 | case PVRDMA_REG_DSRLOW: | |
355 | dev->dsr_info.dma = val; | |
356 | break; | |
357 | case PVRDMA_REG_DSRHIGH: | |
358 | dev->dsr_info.dma |= val << 32; | |
359 | load_dsr(dev); | |
360 | init_dsr_dev_caps(dev); | |
361 | break; | |
362 | case PVRDMA_REG_CTL: | |
363 | switch (val) { | |
364 | case PVRDMA_DEVICE_CTL_ACTIVATE: | |
365 | activate_device(dev); | |
366 | break; | |
367 | case PVRDMA_DEVICE_CTL_UNQUIESCE: | |
368 | unquiesce_device(dev); | |
369 | break; | |
370 | case PVRDMA_DEVICE_CTL_RESET: | |
371 | reset_device(dev); | |
372 | break; | |
373 | } | |
374 | break; | |
375 | case PVRDMA_REG_IMR: | |
376 | pr_dbg("Interrupt mask=0x%lx\n", val); | |
377 | dev->interrupt_mask = val; | |
378 | break; | |
379 | case PVRDMA_REG_REQUEST: | |
380 | if (val == 0) { | |
381 | execute_command(dev); | |
382 | } | |
383 | break; | |
384 | default: | |
385 | break; | |
386 | } | |
387 | } | |
388 | ||
389 | static const MemoryRegionOps regs_ops = { | |
390 | .read = regs_read, | |
391 | .write = regs_write, | |
392 | .endianness = DEVICE_LITTLE_ENDIAN, | |
393 | .impl = { | |
394 | .min_access_size = sizeof(uint32_t), | |
395 | .max_access_size = sizeof(uint32_t), | |
396 | }, | |
397 | }; | |
398 | ||
399 | static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
400 | { | |
401 | PVRDMADev *dev = opaque; | |
402 | ||
403 | /* pr_dbg("addr=0x%lx, val=0x%x, size=%d\n", addr, (uint32_t)val, size); */ | |
404 | ||
405 | switch (addr & 0xFFF) { /* Mask with 0xFFF as each UC gets page */ | |
406 | case PVRDMA_UAR_QP_OFFSET: | |
407 | pr_dbg("UAR QP command, addr=0x%x, val=0x%lx\n", (uint32_t)addr, val); | |
408 | if (val & PVRDMA_UAR_QP_SEND) { | |
409 | pvrdma_qp_send(dev, val & PVRDMA_UAR_HANDLE_MASK); | |
410 | } | |
411 | if (val & PVRDMA_UAR_QP_RECV) { | |
412 | pvrdma_qp_recv(dev, val & PVRDMA_UAR_HANDLE_MASK); | |
413 | } | |
414 | break; | |
415 | case PVRDMA_UAR_CQ_OFFSET: | |
416 | /* pr_dbg("UAR CQ cmd, addr=0x%x, val=0x%lx\n", (uint32_t)addr, val); */ | |
417 | if (val & PVRDMA_UAR_CQ_ARM) { | |
418 | rdma_rm_req_notify_cq(&dev->rdma_dev_res, | |
419 | val & PVRDMA_UAR_HANDLE_MASK, | |
420 | !!(val & PVRDMA_UAR_CQ_ARM_SOL)); | |
421 | } | |
422 | if (val & PVRDMA_UAR_CQ_ARM_SOL) { | |
423 | pr_dbg("UAR_CQ_ARM_SOL (%ld)\n", val & PVRDMA_UAR_HANDLE_MASK); | |
424 | } | |
425 | if (val & PVRDMA_UAR_CQ_POLL) { | |
426 | pr_dbg("UAR_CQ_POLL (%ld)\n", val & PVRDMA_UAR_HANDLE_MASK); | |
427 | pvrdma_cq_poll(&dev->rdma_dev_res, val & PVRDMA_UAR_HANDLE_MASK); | |
428 | } | |
429 | break; | |
430 | default: | |
431 | pr_err("Unsupported command, addr=0x%lx, val=0x%lx\n", | |
432 | (uint64_t)addr, val); | |
433 | break; | |
434 | } | |
435 | } | |
436 | ||
437 | static const MemoryRegionOps uar_ops = { | |
438 | .write = uar_write, | |
439 | .endianness = DEVICE_LITTLE_ENDIAN, | |
440 | .impl = { | |
441 | .min_access_size = sizeof(uint32_t), | |
442 | .max_access_size = sizeof(uint32_t), | |
443 | }, | |
444 | }; | |
445 | ||
446 | static void init_pci_config(PCIDevice *pdev) | |
447 | { | |
448 | pdev->config[PCI_INTERRUPT_PIN] = 1; | |
449 | } | |
450 | ||
451 | static void init_bars(PCIDevice *pdev) | |
452 | { | |
453 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
454 | ||
455 | /* BAR 0 - MSI-X */ | |
456 | memory_region_init(&dev->msix, OBJECT(dev), "pvrdma-msix", | |
457 | RDMA_BAR0_MSIX_SIZE); | |
458 | pci_register_bar(pdev, RDMA_MSIX_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, | |
459 | &dev->msix); | |
460 | ||
461 | /* BAR 1 - Registers */ | |
462 | memset(&dev->regs_data, 0, sizeof(dev->regs_data)); | |
463 | memory_region_init_io(&dev->regs, OBJECT(dev), ®s_ops, dev, | |
464 | "pvrdma-regs", RDMA_BAR1_REGS_SIZE); | |
465 | pci_register_bar(pdev, RDMA_REG_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, | |
466 | &dev->regs); | |
467 | ||
468 | /* BAR 2 - UAR */ | |
469 | memset(&dev->uar_data, 0, sizeof(dev->uar_data)); | |
470 | memory_region_init_io(&dev->uar, OBJECT(dev), &uar_ops, dev, "rdma-uar", | |
471 | RDMA_BAR2_UAR_SIZE); | |
472 | pci_register_bar(pdev, RDMA_UAR_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, | |
473 | &dev->uar); | |
474 | } | |
475 | ||
476 | static void init_regs(PCIDevice *pdev) | |
477 | { | |
478 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
479 | ||
480 | set_reg_val(dev, PVRDMA_REG_VERSION, PVRDMA_HW_VERSION); | |
481 | set_reg_val(dev, PVRDMA_REG_ERR, 0xFFFF); | |
482 | } | |
483 | ||
484 | static void uninit_msix(PCIDevice *pdev, int used_vectors) | |
485 | { | |
486 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
487 | int i; | |
488 | ||
489 | for (i = 0; i < used_vectors; i++) { | |
490 | msix_vector_unuse(pdev, i); | |
491 | } | |
492 | ||
493 | msix_uninit(pdev, &dev->msix, &dev->msix); | |
494 | } | |
495 | ||
496 | static int init_msix(PCIDevice *pdev, Error **errp) | |
497 | { | |
498 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
499 | int i; | |
500 | int rc; | |
501 | ||
502 | rc = msix_init(pdev, RDMA_MAX_INTRS, &dev->msix, RDMA_MSIX_BAR_IDX, | |
503 | RDMA_MSIX_TABLE, &dev->msix, RDMA_MSIX_BAR_IDX, | |
504 | RDMA_MSIX_PBA, 0, NULL); | |
505 | ||
506 | if (rc < 0) { | |
507 | error_setg(errp, "Failed to initialize MSI-X"); | |
508 | return rc; | |
509 | } | |
510 | ||
511 | for (i = 0; i < RDMA_MAX_INTRS; i++) { | |
512 | rc = msix_vector_use(PCI_DEVICE(dev), i); | |
513 | if (rc < 0) { | |
514 | error_setg(errp, "Fail mark MSI-X vercor %d", i); | |
515 | uninit_msix(pdev, i); | |
516 | return rc; | |
517 | } | |
518 | } | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
523 | static void init_dev_caps(PVRDMADev *dev) | |
524 | { | |
525 | size_t pg_tbl_bytes = TARGET_PAGE_SIZE * | |
526 | (TARGET_PAGE_SIZE / sizeof(uint64_t)); | |
527 | size_t wr_sz = MAX(sizeof(struct pvrdma_sq_wqe_hdr), | |
528 | sizeof(struct pvrdma_rq_wqe_hdr)); | |
529 | ||
530 | dev->dev_attr.max_qp_wr = pg_tbl_bytes / | |
531 | (wr_sz + sizeof(struct pvrdma_sge) * MAX_SGE) - | |
532 | TARGET_PAGE_SIZE; /* First page is ring state */ | |
533 | pr_dbg("max_qp_wr=%d\n", dev->dev_attr.max_qp_wr); | |
534 | ||
535 | dev->dev_attr.max_cqe = pg_tbl_bytes / sizeof(struct pvrdma_cqe) - | |
536 | TARGET_PAGE_SIZE; /* First page is ring state */ | |
537 | pr_dbg("max_cqe=%d\n", dev->dev_attr.max_cqe); | |
538 | } | |
539 | ||
540 | static int pvrdma_check_ram_shared(Object *obj, void *opaque) | |
541 | { | |
542 | bool *shared = opaque; | |
543 | ||
544 | if (object_dynamic_cast(obj, "memory-backend-ram")) { | |
545 | *shared = object_property_get_bool(obj, "share", NULL); | |
546 | } | |
547 | ||
548 | return 0; | |
549 | } | |
550 | ||
551 | static void pvrdma_realize(PCIDevice *pdev, Error **errp) | |
552 | { | |
553 | int rc; | |
554 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
555 | Object *memdev_root; | |
556 | bool ram_shared = false; | |
557 | ||
558 | pr_dbg("Initializing device %s %x.%x\n", pdev->name, | |
559 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | |
560 | ||
561 | if (TARGET_PAGE_SIZE != getpagesize()) { | |
562 | error_setg(errp, "Target page size must be the same as host page size"); | |
563 | return; | |
564 | } | |
565 | ||
566 | memdev_root = object_resolve_path("/objects", NULL); | |
567 | if (memdev_root) { | |
568 | object_child_foreach(memdev_root, pvrdma_check_ram_shared, &ram_shared); | |
569 | } | |
570 | if (!ram_shared) { | |
571 | error_setg(errp, "Only shared memory backed ram is supported"); | |
572 | return; | |
573 | } | |
574 | ||
575 | dev->dsr_info.dsr = NULL; | |
576 | ||
577 | init_pci_config(pdev); | |
578 | ||
579 | init_bars(pdev); | |
580 | ||
581 | init_regs(pdev); | |
582 | ||
583 | init_dev_caps(dev); | |
584 | ||
585 | rc = init_msix(pdev, errp); | |
586 | if (rc) { | |
587 | goto out; | |
588 | } | |
589 | ||
590 | rc = rdma_backend_init(&dev->backend_dev, &dev->rdma_dev_res, | |
591 | dev->backend_device_name, dev->backend_port_num, | |
592 | dev->backend_gid_idx, &dev->dev_attr, errp); | |
593 | if (rc) { | |
594 | goto out; | |
595 | } | |
596 | ||
597 | rc = rdma_rm_init(&dev->rdma_dev_res, &dev->dev_attr, errp); | |
598 | if (rc) { | |
599 | goto out; | |
600 | } | |
601 | ||
602 | init_ports(dev, errp); | |
603 | ||
604 | rc = pvrdma_qp_ops_init(); | |
605 | if (rc) { | |
606 | goto out; | |
607 | } | |
608 | ||
609 | out: | |
610 | if (rc) { | |
611 | error_append_hint(errp, "Device fail to load\n"); | |
612 | } | |
613 | } | |
614 | ||
615 | static void pvrdma_exit(PCIDevice *pdev) | |
616 | { | |
617 | PVRDMADev *dev = PVRDMA_DEV(pdev); | |
618 | ||
619 | pr_dbg("Closing device %s %x.%x\n", pdev->name, PCI_SLOT(pdev->devfn), | |
620 | PCI_FUNC(pdev->devfn)); | |
621 | ||
622 | pvrdma_qp_ops_fini(); | |
623 | ||
624 | free_ports(dev); | |
625 | ||
626 | rdma_rm_fini(&dev->rdma_dev_res); | |
627 | ||
628 | rdma_backend_fini(&dev->backend_dev); | |
629 | ||
630 | free_dsr(dev); | |
631 | ||
632 | if (msix_enabled(pdev)) { | |
633 | uninit_msix(pdev, RDMA_MAX_INTRS); | |
634 | } | |
635 | } | |
636 | ||
637 | static void pvrdma_class_init(ObjectClass *klass, void *data) | |
638 | { | |
639 | DeviceClass *dc = DEVICE_CLASS(klass); | |
640 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
641 | ||
642 | k->realize = pvrdma_realize; | |
643 | k->exit = pvrdma_exit; | |
644 | k->vendor_id = PCI_VENDOR_ID_VMWARE; | |
645 | k->device_id = PCI_DEVICE_ID_VMWARE_PVRDMA; | |
646 | k->revision = 0x00; | |
647 | k->class_id = PCI_CLASS_NETWORK_OTHER; | |
648 | ||
649 | dc->desc = "RDMA Device"; | |
650 | dc->props = pvrdma_dev_properties; | |
651 | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); | |
652 | } | |
653 | ||
654 | static const TypeInfo pvrdma_info = { | |
655 | .name = PVRDMA_HW_NAME, | |
656 | .parent = TYPE_PCI_DEVICE, | |
657 | .instance_size = sizeof(PVRDMADev), | |
658 | .class_init = pvrdma_class_init, | |
659 | .interfaces = (InterfaceInfo[]) { | |
660 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
661 | { } | |
662 | } | |
663 | }; | |
664 | ||
665 | static void register_types(void) | |
666 | { | |
667 | type_register_static(&pvrdma_info); | |
668 | } | |
669 | ||
670 | type_init(register_types) |