Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "vmd_internal.h"
7 : :
8 : : #include "spdk/stdinc.h"
9 : : #include "spdk/string.h"
10 : : #include "spdk/likely.h"
11 : :
12 : : static unsigned char *device_type[] = {
13 : : "PCI Express Endpoint",
14 : : "Legacy PCI Express Endpoint",
15 : : "Reserved 1",
16 : : "Reserved 2",
17 : : "Root Port of PCI Express Root Complex",
18 : : "Upstream Port of PCI Express Switch",
19 : : "Downstream Port of PCI Express Switch",
20 : : "PCI Express to PCI/PCI-X Bridge",
21 : : "PCI/PCI-X to PCI Express Bridge",
22 : : "Root Complex Integrated Endpoint",
23 : : "Root Complex Event Collector",
24 : : "Reserved Capability"
25 : : };
26 : :
27 : : /*
28 : : * Container for all VMD adapter probed in the system.
29 : : */
30 : : struct vmd_container {
31 : : uint32_t count;
32 : : struct vmd_adapter vmd[MAX_VMD_SUPPORTED];
33 : : };
34 : :
35 : : static struct vmd_container g_vmd_container;
36 : : static uint8_t g_end_device_count;
37 : :
38 : : static bool
39 : 2688 : vmd_is_valid_cfg_addr(struct vmd_pci_bus *bus, uint64_t addr)
40 : : {
41 [ + - ]: 5376 : return addr >= (uint64_t)bus->vmd->cfg_vaddr &&
42 [ + - ]: 2688 : addr < bus->vmd->cfgbar_size + (uint64_t)bus->vmd->cfg_vaddr;
43 : : }
44 : :
45 : : static void
46 : 6 : vmd_align_base_addrs(struct vmd_adapter *vmd, uint32_t alignment)
47 : : {
48 : : uint32_t pad;
49 : :
50 : : /*
51 : : * Device is not in hot plug path, align the base address remaining from membar 1.
52 : : */
53 [ - + ]: 6 : if (vmd->physical_addr & (alignment - 1)) {
54 : 0 : pad = alignment - (vmd->physical_addr & (alignment - 1));
55 : 0 : vmd->physical_addr += pad;
56 : 0 : vmd->current_addr_size -= pad;
57 : : }
58 : 6 : }
59 : :
60 : : static bool
61 : 66 : vmd_device_is_enumerated(volatile struct pci_header *header)
62 : : {
63 [ + - ]: 132 : return header->one.prefetch_base_upper == VMD_UPPER_BASE_SIGNATURE &&
64 [ + - ]: 66 : header->one.prefetch_limit_upper == VMD_UPPER_LIMIT_SIGNATURE;
65 : : }
66 : :
67 : : static bool
68 : 114 : vmd_device_is_root_port(volatile struct pci_header *header)
69 : : {
70 [ + - ]: 228 : return header->common.vendor_id == SPDK_PCI_VID_INTEL &&
71 [ + + ]: 114 : (header->common.device_id == PCI_ROOT_PORT_A_INTEL_SKX ||
72 [ + + ]: 96 : header->common.device_id == PCI_ROOT_PORT_B_INTEL_SKX ||
73 [ + + ]: 84 : header->common.device_id == PCI_ROOT_PORT_C_INTEL_SKX ||
74 [ - + ]: 36 : header->common.device_id == PCI_ROOT_PORT_D_INTEL_SKX ||
75 [ # # ]: 0 : header->common.device_id == PCI_ROOT_PORT_A_INTEL_ICX ||
76 [ # # ]: 0 : header->common.device_id == PCI_ROOT_PORT_B_INTEL_ICX ||
77 [ # # ]: 0 : header->common.device_id == PCI_ROOT_PORT_C_INTEL_ICX ||
78 [ # # ]: 0 : header->common.device_id == PCI_ROOT_PORT_D_INTEL_ICX);
79 : : }
80 : :
81 : : static void
82 : 11 : vmd_hotplug_coalesce_regions(struct vmd_hot_plug *hp)
83 : : {
84 : : struct pci_mem_mgr *region, *prev;
85 : :
86 : : do {
87 : 16 : prev = NULL;
88 [ + + ]: 32 : TAILQ_FOREACH(region, &hp->free_mem_queue, tailq) {
89 [ + + + - ]: 21 : if (prev != NULL && (prev->addr + prev->size == region->addr)) {
90 : 5 : break;
91 : : }
92 : :
93 : 16 : prev = region;
94 : : }
95 : :
96 [ + + ]: 16 : if (region != NULL) {
97 : 5 : prev->size += region->size;
98 [ - + ]: 5 : TAILQ_REMOVE(&hp->free_mem_queue, region, tailq);
99 : 5 : TAILQ_INSERT_TAIL(&hp->unused_mem_queue, region, tailq);
100 : : }
101 [ + + ]: 16 : } while (region != NULL);
102 : 11 : }
103 : :
104 : : static void
105 : 11 : vmd_hotplug_free_region(struct vmd_hot_plug *hp, struct pci_mem_mgr *region)
106 : : {
107 : 11 : struct pci_mem_mgr *current, *prev = NULL;
108 : :
109 [ + - + - ]: 11 : assert(region->addr >= hp->bar.start && region->addr < hp->bar.start + hp->bar.size);
110 : :
111 [ + + ]: 11 : TAILQ_FOREACH(current, &hp->free_mem_queue, tailq) {
112 [ + - ]: 5 : if (current->addr > region->addr) {
113 : 5 : break;
114 : : }
115 : :
116 : 0 : prev = current;
117 : : }
118 : :
119 [ - + ]: 11 : if (prev != NULL) {
120 [ # # ]: 0 : assert(prev->addr + prev->size <= region->addr);
121 [ # # # # ]: 0 : assert(current == NULL || (region->addr + region->size <= current->addr));
122 [ # # ]: 0 : TAILQ_INSERT_AFTER(&hp->free_mem_queue, prev, region, tailq);
123 : : } else {
124 [ + + ]: 11 : TAILQ_INSERT_HEAD(&hp->free_mem_queue, region, tailq);
125 : : }
126 : :
127 : 11 : vmd_hotplug_coalesce_regions(hp);
128 : 11 : }
129 : :
130 : : static void
131 : 5 : vmd_hotplug_free_addr(struct vmd_hot_plug *hp, uint64_t addr)
132 : : {
133 : : struct pci_mem_mgr *region;
134 : :
135 [ + - ]: 5 : TAILQ_FOREACH(region, &hp->alloc_mem_queue, tailq) {
136 [ + - ]: 5 : if (region->addr == addr) {
137 : 5 : break;
138 : : }
139 : : }
140 : :
141 [ - + ]: 5 : assert(region != NULL);
142 [ - + ]: 5 : TAILQ_REMOVE(&hp->alloc_mem_queue, region, tailq);
143 : :
144 : 5 : vmd_hotplug_free_region(hp, region);
145 : 5 : }
146 : :
147 : : static uint64_t
148 : 6 : vmd_hotplug_allocate_base_addr(struct vmd_hot_plug *hp, uint32_t size)
149 : : {
150 : 6 : struct pci_mem_mgr *region = NULL, *free_region;
151 : :
152 [ + - ]: 6 : TAILQ_FOREACH(region, &hp->free_mem_queue, tailq) {
153 [ + - ]: 6 : if (region->size >= size) {
154 : 6 : break;
155 : : }
156 : : }
157 : :
158 [ - + ]: 6 : if (region == NULL) {
159 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "Unable to find free hotplug memory region of size:"
160 : : "%"PRIx32"\n", size);
161 : 0 : return 0;
162 : : }
163 : :
164 [ - + ]: 6 : TAILQ_REMOVE(&hp->free_mem_queue, region, tailq);
165 [ + - ]: 6 : if (size < region->size) {
166 : 6 : free_region = TAILQ_FIRST(&hp->unused_mem_queue);
167 [ - + ]: 6 : if (free_region == NULL) {
168 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "Unable to find unused descriptor to store the "
169 : : "free region of size: %"PRIu32"\n", region->size - size);
170 : : } else {
171 [ + - ]: 6 : TAILQ_REMOVE(&hp->unused_mem_queue, free_region, tailq);
172 : 6 : free_region->size = region->size - size;
173 : 6 : free_region->addr = region->addr + size;
174 : 6 : region->size = size;
175 : 6 : vmd_hotplug_free_region(hp, free_region);
176 : : }
177 : : }
178 : :
179 : 6 : TAILQ_INSERT_TAIL(&hp->alloc_mem_queue, region, tailq);
180 : :
181 : 6 : return region->addr;
182 : : }
183 : :
184 : : /*
185 : : * Allocates an address from vmd membar for the input memory size
186 : : * vmdAdapter - vmd adapter object
187 : : * dev - vmd_pci_device to allocate a base address for.
188 : : * size - size of the memory window requested.
189 : : * Size must be an integral multiple of 2. Addresses are returned on the size boundary.
190 : : * Returns physical address within the VMD membar window, or 0x0 if cannot allocate window.
191 : : * Consider increasing the size of vmd membar if 0x0 is returned.
192 : : */
193 : : static uint64_t
194 : 0 : vmd_allocate_base_addr(struct vmd_adapter *vmd, struct vmd_pci_device *dev, uint32_t size)
195 : : {
196 : 0 : uint64_t base_address = 0, padding = 0;
197 : : struct vmd_pci_bus *hp_bus;
198 : :
199 [ # # # # ]: 0 : if (size && ((size & (~size + 1)) != size)) {
200 : 0 : return base_address;
201 : : }
202 : :
203 : : /*
204 : : * If device is downstream of a hot plug port, allocate address from the
205 : : * range dedicated for the hot plug slot. Search the list of addresses allocated to determine
206 : : * if a free range exists that satisfy the input request. If a free range cannot be found,
207 : : * get a buffer from the unused chunk. First fit algorithm, is used.
208 : : */
209 [ # # ]: 0 : if (dev) {
210 : 0 : hp_bus = dev->parent;
211 [ # # # # : 0 : if (hp_bus && hp_bus->self && hp_bus->self->hotplug_capable) {
# # # # ]
212 : 0 : return vmd_hotplug_allocate_base_addr(&hp_bus->self->hp, size);
213 : : }
214 : : }
215 : :
216 : : /* Ensure physical membar allocated is size aligned */
217 [ # # ]: 0 : if (vmd->physical_addr & (size - 1)) {
218 : 0 : padding = size - (vmd->physical_addr & (size - 1));
219 : : }
220 : :
221 : : /* Allocate from membar if enough memory is left */
222 [ # # ]: 0 : if (vmd->current_addr_size >= size + padding) {
223 : 0 : base_address = vmd->physical_addr + padding;
224 : 0 : vmd->physical_addr += size + padding;
225 : 0 : vmd->current_addr_size -= size + padding;
226 : : }
227 : :
228 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "allocated(size) %" PRIx64 " (%x)\n", base_address, size);
229 : :
230 : 0 : return base_address;
231 : : }
232 : :
233 : : static bool
234 : 6 : vmd_is_end_device(struct vmd_pci_device *dev)
235 : : {
236 [ + - + - ]: 12 : return (dev && dev->header) &&
237 [ + - ]: 6 : ((dev->header->common.header_type & ~PCI_MULTI_FUNCTION) == PCI_HEADER_TYPE_NORMAL);
238 : : }
239 : :
240 : : static void
241 : 6 : vmd_update_base_limit_register(struct vmd_pci_device *dev, uint16_t base, uint16_t limit)
242 : : {
243 : : struct vmd_pci_bus *bus;
244 : : struct vmd_pci_device *bridge;
245 : :
246 [ + - - + ]: 6 : if (base == 0 || limit == 0) {
247 : 0 : return;
248 : : }
249 : :
250 [ - + ]: 6 : if (dev->header->common.header_type == PCI_HEADER_TYPE_BRIDGE) {
251 : 0 : bus = dev->bus_object;
252 : : } else {
253 : 6 : bus = dev->parent;
254 : : }
255 : :
256 : 6 : bridge = bus->self;
257 [ - + - + ]: 6 : SPDK_INFOLOG(vmd, "base:limit = %x:%x\n", bridge->header->one.mem_base,
258 : : bridge->header->one.mem_limit);
259 : :
260 [ + - ]: 6 : if (dev->bus->vmd->scan_completed) {
261 : 6 : return;
262 : : }
263 : :
264 [ # # # # ]: 0 : while (bus && bus->self != NULL) {
265 : 0 : bridge = bus->self;
266 : :
267 : : /* This is only for 32-bit memory space, need to revisit to support 64-bit */
268 [ # # ]: 0 : if (bridge->header->one.mem_base > base) {
269 : 0 : bridge->header->one.mem_base = base;
270 : 0 : base = bridge->header->one.mem_base;
271 : : }
272 : :
273 [ # # ]: 0 : if (bridge->header->one.mem_limit < limit) {
274 : 0 : bridge->header->one.mem_limit = limit;
275 : 0 : limit = bridge->header->one.mem_limit;
276 : : }
277 : :
278 : 0 : bus = bus->parent;
279 : : }
280 : : }
281 : :
282 : : static uint64_t
283 : 6 : vmd_get_base_addr(struct vmd_pci_device *dev, uint32_t index, uint32_t size)
284 : : {
285 : 6 : struct vmd_pci_bus *bus = dev->parent;
286 : :
287 [ - + ]: 6 : if (dev->header_type == PCI_HEADER_TYPE_BRIDGE) {
288 : 0 : return dev->header->zero.BAR[index] & ~0xf;
289 : : } else {
290 [ - + + - ]: 6 : if (bus->self->hotplug_capable) {
291 : 6 : return vmd_hotplug_allocate_base_addr(&bus->self->hp, size);
292 : : } else {
293 : 0 : return (uint64_t)bus->self->header->one.mem_base << 16;
294 : : }
295 : : }
296 : : }
297 : :
298 : : static bool
299 : 6 : vmd_assign_base_addrs(struct vmd_pci_device *dev)
300 : : {
301 : 6 : uint16_t mem_base = 0, mem_limit = 0;
302 : 6 : unsigned char mem_attr = 0;
303 : : int last;
304 : 6 : struct vmd_adapter *vmd = NULL;
305 : 6 : bool ret_val = false;
306 : : uint32_t bar_value;
307 : : uint32_t table_offset;
308 : :
309 [ + - + - ]: 6 : if (dev && dev->bus) {
310 : 6 : vmd = dev->bus->vmd;
311 : : }
312 : :
313 [ - + ]: 6 : if (!vmd) {
314 : 0 : return 0;
315 : : }
316 : :
317 : 6 : vmd_align_base_addrs(vmd, ONE_MB);
318 : :
319 [ - + ]: 6 : last = dev->header_type ? 2 : 6;
320 [ + + ]: 42 : for (int i = 0; i < last; i++) {
321 : 36 : bar_value = dev->header->zero.BAR[i];
322 : 36 : dev->header->zero.BAR[i] = ~(0U);
323 : 36 : dev->bar[i].size = dev->header->zero.BAR[i];
324 : 36 : dev->header->zero.BAR[i] = bar_value;
325 : :
326 [ + + + + ]: 36 : if (dev->bar[i].size == ~(0U) || dev->bar[i].size == 0 ||
327 [ - + ]: 6 : dev->header->zero.BAR[i] & 1) {
328 : 30 : dev->bar[i].size = 0;
329 : 30 : continue;
330 : : }
331 : 6 : mem_attr = dev->bar[i].size & PCI_BASE_ADDR_MASK;
332 : 6 : dev->bar[i].size = TWOS_COMPLEMENT(dev->bar[i].size & PCI_BASE_ADDR_MASK);
333 : :
334 [ + - ]: 6 : if (vmd->scan_completed) {
335 : 6 : dev->bar[i].start = vmd_get_base_addr(dev, i, dev->bar[i].size);
336 : : } else {
337 : 0 : dev->bar[i].start = vmd_allocate_base_addr(vmd, dev, dev->bar[i].size);
338 : : }
339 : :
340 : 6 : dev->header->zero.BAR[i] = (uint32_t)dev->bar[i].start;
341 : :
342 [ - + ]: 6 : if (!dev->bar[i].start) {
343 [ # # ]: 0 : if (mem_attr == (PCI_BAR_MEMORY_PREFETCH | PCI_BAR_MEMORY_TYPE_64)) {
344 : 0 : i++;
345 : : }
346 : 0 : continue;
347 : : }
348 : :
349 : 6 : dev->bar[i].vaddr = ((uint64_t)vmd->mem_vaddr + (dev->bar[i].start - vmd->membar));
350 : 6 : mem_limit = BRIDGE_BASEREG(dev->header->zero.BAR[i]) +
351 : 6 : BRIDGE_BASEREG(dev->bar[i].size - 1);
352 [ + - ]: 6 : if (!mem_base) {
353 : 6 : mem_base = BRIDGE_BASEREG(dev->header->zero.BAR[i]);
354 : : }
355 : :
356 : 6 : ret_val = true;
357 : :
358 [ - + ]: 6 : if (mem_attr == (PCI_BAR_MEMORY_PREFETCH | PCI_BAR_MEMORY_TYPE_64)) {
359 : 0 : i++;
360 [ # # ]: 0 : if (i < last) {
361 : 0 : dev->header->zero.BAR[i] = (uint32_t)(dev->bar[i].start >> PCI_DWORD_SHIFT);
362 : : }
363 : : }
364 : : }
365 : :
366 : : /* Enable device MEM and bus mastering */
367 : 6 : dev->header->zero.command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
368 : : /*
369 : : * Writes to the pci config space is posted write. To ensure transaction reaches its destination
370 : : * before another write is posed, an immediate read of the written value should be performed.
371 : : */
372 : 6 : { uint16_t cmd = dev->header->zero.command; (void)cmd; }
373 : :
374 [ + - + - ]: 6 : if (dev->msix_cap && ret_val) {
375 : 6 : table_offset = ((volatile struct pci_msix_cap *)dev->msix_cap)->msix_table_offset;
376 [ + - ]: 6 : if (dev->bar[table_offset & 0x3].vaddr) {
377 : 6 : dev->msix_table = (volatile struct pci_msix_table_entry *)
378 : 6 : (dev->bar[table_offset & 0x3].vaddr + (table_offset & 0xfff8));
379 : : }
380 : : }
381 : :
382 [ + - + - ]: 6 : if (ret_val && vmd_is_end_device(dev)) {
383 : 6 : vmd_update_base_limit_register(dev, mem_base, mem_limit);
384 : : }
385 : :
386 : 6 : return ret_val;
387 : : }
388 : :
389 : : static void
390 : 54 : vmd_get_device_capabilities(struct vmd_pci_device *dev)
391 : :
392 : : {
393 : : volatile uint8_t *config_space;
394 : : uint8_t capabilities_offset;
395 : : struct pci_capabilities_header *capabilities_hdr;
396 : :
397 : 54 : config_space = (volatile uint8_t *)dev->header;
398 [ - + ]: 54 : if ((dev->header->common.status & PCI_CAPABILITIES_LIST) == 0) {
399 : 0 : return;
400 : : }
401 : :
402 : 54 : capabilities_offset = dev->header->zero.cap_pointer;
403 [ + + ]: 54 : if (dev->header->common.header_type & PCI_HEADER_TYPE_BRIDGE) {
404 : 48 : capabilities_offset = dev->header->one.cap_pointer;
405 : : }
406 : :
407 [ + + ]: 270 : while (capabilities_offset > 0) {
408 : 432 : capabilities_hdr = (struct pci_capabilities_header *)
409 : 216 : &config_space[capabilities_offset];
410 [ + + + + ]: 216 : switch (capabilities_hdr->capability_id) {
411 : 54 : case CAPABILITY_ID_PCI_EXPRESS:
412 : 54 : dev->pcie_cap = (volatile struct pci_express_cap *)(capabilities_hdr);
413 : 54 : break;
414 : :
415 : 54 : case CAPABILITY_ID_MSI:
416 : 54 : dev->msi_cap = (volatile struct pci_msi_cap *)capabilities_hdr;
417 : 54 : break;
418 : :
419 : 6 : case CAPABILITY_ID_MSIX:
420 : 6 : dev->msix_cap = (volatile struct pci_msix_capability *)capabilities_hdr;
421 : 6 : dev->msix_table_size = dev->msix_cap->message_control.bit.table_size + 1;
422 : 6 : break;
423 : :
424 : 102 : default:
425 : 102 : break;
426 : : }
427 : 216 : capabilities_offset = capabilities_hdr->next;
428 : : }
429 : : }
430 : :
431 : : static volatile struct pci_enhanced_capability_header *
432 : 54 : vmd_get_enhanced_capabilities(struct vmd_pci_device *dev, uint16_t capability_id)
433 : : {
434 : : uint8_t *data;
435 : 54 : uint16_t cap_offset = EXTENDED_CAPABILITY_OFFSET;
436 : 54 : volatile struct pci_enhanced_capability_header *cap_hdr = NULL;
437 : :
438 : 54 : data = (uint8_t *)dev->header;
439 [ + - ]: 414 : while (cap_offset >= EXTENDED_CAPABILITY_OFFSET) {
440 : 414 : cap_hdr = (volatile struct pci_enhanced_capability_header *) &data[cap_offset];
441 [ + + ]: 414 : if (cap_hdr->capability_id == capability_id) {
442 : 6 : return cap_hdr;
443 : : }
444 : 408 : cap_offset = cap_hdr->next;
445 [ + + + - ]: 408 : if (cap_offset == 0 || cap_offset < EXTENDED_CAPABILITY_OFFSET) {
446 : : break;
447 : : }
448 : : }
449 : :
450 : 48 : return NULL;
451 : : }
452 : :
453 : : static void
454 : 54 : vmd_read_config_space(struct vmd_pci_device *dev)
455 : : {
456 : : /*
457 : : * Writes to the pci config space is posted weite. To ensure transaction reaches its destination
458 : : * before another write is posed, an immediate read of the written value should be performed.
459 : : */
460 : 54 : dev->header->common.command |= (BUS_MASTER_ENABLE | MEMORY_SPACE_ENABLE);
461 : 54 : { uint16_t cmd = dev->header->common.command; (void)cmd; }
462 : :
463 : 54 : vmd_get_device_capabilities(dev);
464 : 54 : dev->sn_cap = (struct serial_number_capability *)vmd_get_enhanced_capabilities(dev,
465 : : DEVICE_SERIAL_NUMBER_CAP_ID);
466 : 54 : }
467 : :
468 : : static void
469 : 48 : vmd_update_scan_info(struct vmd_pci_device *dev)
470 : : {
471 : 48 : struct vmd_adapter *vmd_adapter = dev->bus->vmd;
472 : :
473 [ + + ]: 48 : if (vmd_adapter->root_port_updated) {
474 : 30 : return;
475 : : }
476 : :
477 [ - + ]: 18 : if (dev->header_type == PCI_HEADER_TYPE_NORMAL) {
478 : 0 : return;
479 : : }
480 : :
481 [ + - ]: 18 : if (vmd_device_is_root_port(dev->header)) {
482 : 18 : vmd_adapter->root_port_updated = 1;
483 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "root_port_updated = %d\n",
484 : : vmd_adapter->root_port_updated);
485 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "upper:limit = %x : %x\n",
486 : : dev->header->one.prefetch_base_upper,
487 : : dev->header->one.prefetch_limit_upper);
488 [ + - ]: 18 : if (vmd_device_is_enumerated(dev->header)) {
489 : 18 : vmd_adapter->scan_completed = 1;
490 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "scan_completed = %d\n",
491 : : vmd_adapter->scan_completed);
492 : : }
493 : : }
494 : : }
495 : :
496 : : static void
497 : 0 : vmd_reset_base_limit_registers(volatile struct pci_header *header)
498 : : {
499 : : uint32_t reg __attribute__((unused));
500 : :
501 : : /*
502 : : * Writes to the pci config space are posted writes.
503 : : * To ensure transaction reaches its destination
504 : : * before another write is posted, an immediate read
505 : : * of the written value should be performed.
506 : : */
507 : 0 : header->one.mem_base = 0xfff0;
508 : 0 : reg = header->one.mem_base;
509 : 0 : header->one.mem_limit = 0x0;
510 : 0 : reg = header->one.mem_limit;
511 : 0 : header->one.prefetch_base = 0x0;
512 : 0 : reg = header->one.prefetch_base;
513 : 0 : header->one.prefetch_limit = 0x0;
514 : 0 : reg = header->one.prefetch_limit;
515 : 0 : header->one.prefetch_base_upper = 0x0;
516 : 0 : reg = header->one.prefetch_base_upper;
517 : 0 : header->one.prefetch_limit_upper = 0x0;
518 : 0 : reg = header->one.prefetch_limit_upper;
519 : 0 : header->one.io_base_upper = 0x0;
520 : 0 : reg = header->one.io_base_upper;
521 : 0 : header->one.io_limit_upper = 0x0;
522 : 0 : reg = header->one.io_limit_upper;
523 : 0 : header->one.primary = 0;
524 : 0 : reg = header->one.primary;
525 : 0 : header->one.secondary = 0;
526 : 0 : reg = header->one.secondary;
527 : 0 : header->one.subordinate = 0;
528 : 0 : reg = header->one.subordinate;
529 : 0 : }
530 : :
531 : : static void
532 : 12 : vmd_init_hotplug(struct vmd_pci_device *dev, struct vmd_pci_bus *bus)
533 : : {
534 : 12 : struct vmd_adapter *vmd = bus->vmd;
535 : 12 : struct vmd_hot_plug *hp = &dev->hp;
536 : : size_t mem_id;
537 : :
538 : 12 : dev->hotplug_capable = true;
539 : 12 : hp->bar.size = 1 << 20;
540 : :
541 [ - + ]: 12 : if (!vmd->scan_completed) {
542 : 0 : hp->bar.start = vmd_allocate_base_addr(vmd, NULL, hp->bar.size);
543 : 0 : bus->self->header->one.mem_base = BRIDGE_BASEREG(hp->bar.start);
544 : 0 : bus->self->header->one.mem_limit =
545 : 0 : bus->self->header->one.mem_base + BRIDGE_BASEREG(hp->bar.size - 1);
546 : : } else {
547 : 12 : hp->bar.start = (uint64_t)bus->self->header->one.mem_base << 16;
548 : : }
549 : :
550 : 12 : hp->bar.vaddr = (uint64_t)vmd->mem_vaddr + (hp->bar.start - vmd->membar);
551 : :
552 : 12 : TAILQ_INIT(&hp->free_mem_queue);
553 : 12 : TAILQ_INIT(&hp->unused_mem_queue);
554 : 12 : TAILQ_INIT(&hp->alloc_mem_queue);
555 : :
556 : 12 : hp->mem[0].size = hp->bar.size;
557 : 12 : hp->mem[0].addr = hp->bar.start;
558 : :
559 : 12 : TAILQ_INSERT_TAIL(&hp->free_mem_queue, &hp->mem[0], tailq);
560 : :
561 [ + + ]: 384 : for (mem_id = 1; mem_id < ADDR_ELEM_COUNT; ++mem_id) {
562 : 372 : TAILQ_INSERT_TAIL(&hp->unused_mem_queue, &hp->mem[mem_id], tailq);
563 : : }
564 : :
565 [ - + - + ]: 12 : SPDK_INFOLOG(vmd, "%s: mem_base:mem_limit = %x : %x\n", __func__,
566 : : bus->self->header->one.mem_base, bus->self->header->one.mem_limit);
567 : 12 : }
568 : :
569 : : static bool
570 : 2688 : vmd_bus_device_present(struct vmd_pci_bus *bus, uint32_t devfn)
571 : : {
572 : : volatile struct pci_header *header;
573 : :
574 : 2688 : header = (volatile struct pci_header *)(bus->vmd->cfg_vaddr +
575 [ - + ]: 5376 : CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
576 [ - + ]: 2688 : if (!vmd_is_valid_cfg_addr(bus, (uint64_t)header)) {
577 : 0 : return false;
578 : : }
579 : :
580 [ + + - + ]: 2688 : if (header->common.vendor_id == PCI_INVALID_VENDORID || header->common.vendor_id == 0x0) {
581 : 2586 : return false;
582 : : }
583 : :
584 : 102 : return true;
585 : : }
586 : :
587 : : static struct vmd_pci_device *
588 : 2112 : vmd_alloc_dev(struct vmd_pci_bus *bus, uint32_t devfn)
589 : : {
590 : 2112 : struct vmd_pci_device *dev = NULL;
591 : : struct pci_header volatile *header;
592 : : uint8_t header_type;
593 : : uint32_t rev_class;
594 : :
595 : : /* Make sure we're not creating two devices on the same dev/fn */
596 [ + + ]: 2298 : TAILQ_FOREACH(dev, &bus->dev_list, tailq) {
597 [ - + ]: 186 : if (dev->devfn == devfn) {
598 : 0 : return NULL;
599 : : }
600 : : }
601 : :
602 [ + + ]: 2112 : if (!vmd_bus_device_present(bus, devfn)) {
603 : 2058 : return NULL;
604 : : }
605 : :
606 : 54 : header = (struct pci_header * volatile)(bus->vmd->cfg_vaddr +
607 [ - + ]: 108 : CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
608 : :
609 [ - + - + ]: 54 : SPDK_INFOLOG(vmd, "PCI device found: %04x:%04x ***\n",
610 : : header->common.vendor_id, header->common.device_id);
611 : :
612 : 54 : dev = calloc(1, sizeof(*dev));
613 [ - + ]: 54 : if (!dev) {
614 : 0 : return NULL;
615 : : }
616 : :
617 : 54 : dev->header = header;
618 : 54 : dev->vid = dev->header->common.vendor_id;
619 : 54 : dev->did = dev->header->common.device_id;
620 : 54 : dev->bus = bus;
621 : 54 : dev->parent = bus;
622 : 54 : dev->devfn = devfn;
623 : 54 : header_type = dev->header->common.header_type;
624 : 54 : rev_class = dev->header->common.rev_class;
625 : 54 : dev->class = rev_class >> 8;
626 : 54 : dev->header_type = header_type & 0x7;
627 : :
628 [ + + ]: 54 : if (header_type == PCI_HEADER_TYPE_BRIDGE) {
629 : 48 : vmd_update_scan_info(dev);
630 [ - + ]: 48 : if (!dev->bus->vmd->scan_completed) {
631 : 0 : vmd_reset_base_limit_registers(dev->header);
632 : : }
633 : : }
634 : :
635 : 54 : vmd_read_config_space(dev);
636 : :
637 : 54 : return dev;
638 : : }
639 : :
640 : : static struct vmd_pci_bus *
641 : 48 : vmd_create_new_bus(struct vmd_pci_bus *parent, struct vmd_pci_device *bridge, uint8_t bus_number)
642 : : {
643 : : struct vmd_pci_bus *new_bus;
644 : :
645 : 48 : new_bus = calloc(1, sizeof(*new_bus));
646 [ - + ]: 48 : if (!new_bus) {
647 : 0 : return NULL;
648 : : }
649 : :
650 : 48 : new_bus->parent = parent;
651 : 48 : new_bus->domain = parent->domain;
652 : 48 : new_bus->bus_number = bus_number;
653 : 48 : new_bus->secondary_bus = new_bus->subordinate_bus = bus_number;
654 : 48 : new_bus->self = bridge;
655 : 48 : new_bus->vmd = parent->vmd;
656 : 48 : new_bus->config_bus_number = new_bus->bus_number - new_bus->vmd->vmd_bus.bus_start;
657 : 48 : TAILQ_INIT(&new_bus->dev_list);
658 : :
659 : 48 : bridge->subordinate = new_bus;
660 : :
661 : 48 : bridge->pci.addr.bus = new_bus->bus_number;
662 : 48 : bridge->pci.addr.dev = bridge->devfn;
663 : 48 : bridge->pci.addr.func = 0;
664 : 48 : bridge->pci.addr.domain = parent->vmd->pci->addr.domain;
665 : :
666 : 48 : return new_bus;
667 : : }
668 : :
669 : : static uint8_t
670 : 48 : vmd_get_next_bus_number(struct vmd_adapter *vmd)
671 : : {
672 : 48 : uint8_t bus = 0xff;
673 : :
674 [ + - ]: 48 : if ((vmd->next_bus_number + 1) < vmd->max_pci_bus) {
675 : 48 : bus = vmd->next_bus_number;
676 : 48 : vmd->next_bus_number++;
677 : : }
678 : :
679 : 48 : return bus;
680 : : }
681 : :
682 : : static uint8_t
683 : 12 : vmd_get_hotplug_bus_numbers(struct vmd_pci_device *dev)
684 : : {
685 : 12 : uint8_t bus_number = 0xff;
686 : :
687 [ + - + - : 12 : if (dev && dev->bus && dev->bus->vmd &&
+ - ]
688 [ + - ]: 12 : ((dev->bus->vmd->next_bus_number + RESERVED_HOTPLUG_BUSES) < dev->bus->vmd->max_pci_bus)) {
689 : 12 : bus_number = RESERVED_HOTPLUG_BUSES;
690 : 12 : dev->bus->vmd->next_bus_number += RESERVED_HOTPLUG_BUSES;
691 : : }
692 : :
693 : 12 : return bus_number;
694 : : }
695 : :
696 : : static void
697 : 0 : vmd_enable_msix(struct vmd_pci_device *dev)
698 : : {
699 : : volatile uint16_t control;
700 : :
701 : 0 : control = dev->msix_cap->message_control.as_uint16_t | (1 << 14);
702 : 0 : dev->msix_cap->message_control.as_uint16_t = control;
703 : 0 : control = dev->msix_cap->message_control.as_uint16_t;
704 : 0 : dev->msix_cap->message_control.as_uint16_t = (control | (1 << 15));
705 : 0 : control = dev->msix_cap->message_control.as_uint16_t;
706 : 0 : control = control & ~(1 << 14);
707 : 0 : dev->msix_cap->message_control.as_uint16_t = control;
708 : 0 : control = dev->msix_cap->message_control.as_uint16_t;
709 : 0 : }
710 : :
711 : : static void
712 : 0 : vmd_disable_msix(struct vmd_pci_device *dev)
713 : : {
714 : : volatile uint16_t control;
715 : :
716 : 0 : control = dev->msix_cap->message_control.as_uint16_t | (1 << 14);
717 : 0 : dev->msix_cap->message_control.as_uint16_t = control;
718 : 0 : control = dev->msix_cap->message_control.as_uint16_t & ~(1 << 15);
719 : 0 : dev->msix_cap->message_control.as_uint16_t = control;
720 : 0 : control = dev->msix_cap->message_control.as_uint16_t;
721 : 0 : }
722 : :
723 : : /*
724 : : * Set up MSI-X table entries for the port. Vmd MSIX vector 0 is used for
725 : : * port interrupt, so vector 0 is mapped to all MSIX entries for the port.
726 : : */
727 : : static void
728 : 6 : vmd_setup_msix(struct vmd_pci_device *dev, volatile struct pci_msix_table_entry *vmdEntry)
729 : : {
730 : : int entry;
731 : :
732 [ + - - + : 6 : if (!dev || !vmdEntry || !dev->msix_cap) {
- - ]
733 : 6 : return;
734 : : }
735 : :
736 : 0 : vmd_disable_msix(dev);
737 [ # # # # ]: 0 : if (dev->msix_table == NULL || dev->msix_table_size > MAX_MSIX_TABLE_SIZE) {
738 : 0 : return;
739 : : }
740 : :
741 [ # # ]: 0 : for (entry = 0; entry < dev->msix_table_size; ++entry) {
742 : 0 : dev->msix_table[entry].vector_control = 1;
743 : : }
744 : 0 : vmd_enable_msix(dev);
745 : : }
746 : :
747 : : static void
748 : 48 : vmd_bus_update_bridge_info(struct vmd_pci_device *bridge)
749 : : {
750 : : /* Update the subordinate bus of all bridges above this bridge */
751 : 48 : volatile struct vmd_pci_device *dev = bridge;
752 : : uint8_t subordinate_bus;
753 : :
754 [ - + ]: 48 : if (!dev) {
755 : 0 : return;
756 : : }
757 : 48 : subordinate_bus = bridge->header->one.subordinate;
758 [ - + ]: 48 : while (dev->parent_bridge != NULL) {
759 : 0 : dev = dev->parent_bridge;
760 [ # # ]: 0 : if (dev->header->one.subordinate < subordinate_bus) {
761 : 0 : dev->header->one.subordinate = subordinate_bus;
762 : 0 : subordinate_bus = dev->header->one.subordinate;
763 : : }
764 : : }
765 : : }
766 : :
767 : : static bool
768 : 6 : vmd_is_supported_device(struct vmd_pci_device *dev)
769 : : {
770 : 6 : return dev->class == PCI_CLASS_STORAGE_EXPRESS;
771 : : }
772 : :
773 : : static int
774 : 5 : vmd_dev_map_bar(struct spdk_pci_device *pci_dev, uint32_t bar,
775 : : void **mapped_addr, uint64_t *phys_addr, uint64_t *size)
776 : : {
777 : 5 : struct vmd_pci_device *dev = SPDK_CONTAINEROF(pci_dev, struct vmd_pci_device, pci);
778 : :
779 : 5 : *size = dev->bar[bar].size;
780 : 5 : *phys_addr = dev->bar[bar].start;
781 : 5 : *mapped_addr = (void *)dev->bar[bar].vaddr;
782 : :
783 : 5 : return 0;
784 : : }
785 : :
786 : : static int
787 : 5 : vmd_dev_unmap_bar(struct spdk_pci_device *_dev, uint32_t bar, void *addr)
788 : : {
789 : 5 : return 0;
790 : : }
791 : :
792 : : static int
793 : 5 : vmd_dev_cfg_read(struct spdk_pci_device *_dev, void *value, uint32_t len,
794 : : uint32_t offset)
795 : : {
796 : 5 : struct vmd_pci_device *dev = SPDK_CONTAINEROF(_dev, struct vmd_pci_device, pci);
797 : 5 : volatile uint8_t *src = (volatile uint8_t *)dev->header;
798 : 5 : uint8_t *dst = value;
799 : : size_t i;
800 : :
801 [ - + ]: 5 : if (len + offset > PCI_MAX_CFG_SIZE) {
802 : 0 : return -1;
803 : : }
804 : :
805 [ + + ]: 15 : for (i = 0; i < len; ++i) {
806 : 10 : dst[i] = src[offset + i];
807 : : }
808 : :
809 : 5 : return 0;
810 : : }
811 : :
812 : : static int
813 : 5 : vmd_dev_cfg_write(struct spdk_pci_device *_dev, void *value,
814 : : uint32_t len, uint32_t offset)
815 : : {
816 : 5 : struct vmd_pci_device *dev = SPDK_CONTAINEROF(_dev, struct vmd_pci_device, pci);
817 : 5 : volatile uint8_t *dst = (volatile uint8_t *)dev->header;
818 : 5 : uint8_t *src = value;
819 : : size_t i;
820 : :
821 [ - + ]: 5 : if ((len + offset) > PCI_MAX_CFG_SIZE) {
822 : 0 : return -1;
823 : : }
824 : :
825 [ + + ]: 15 : for (i = 0; i < len; ++i) {
826 : 10 : dst[offset + i] = src[i];
827 : : }
828 : :
829 : 5 : return 0;
830 : : }
831 : :
832 : : static void
833 : 5 : vmd_dev_free(struct vmd_pci_device *dev)
834 : : {
835 : 5 : struct vmd_pci_device *bus_device = dev->bus->self;
836 [ - + ]: 5 : size_t i, num_bars = dev->header_type ? 2 : 6;
837 : :
838 : : /* Release the hotplug region if the device is under hotplug-capable bus */
839 [ + - - + : 5 : if (bus_device && bus_device->hotplug_capable) {
+ - ]
840 [ + + ]: 35 : for (i = 0; i < num_bars; ++i) {
841 [ + + ]: 30 : if (dev->bar[i].start != 0) {
842 : 5 : vmd_hotplug_free_addr(&bus_device->hp, dev->bar[i].start);
843 : : }
844 : : }
845 : : }
846 : :
847 : 5 : free(dev);
848 : 5 : }
849 : :
850 : : static void
851 : 5 : vmd_dev_detach(struct spdk_pci_device *dev)
852 : : {
853 : 5 : struct vmd_pci_device *vmd_device = (struct vmd_pci_device *)dev;
854 : 5 : struct vmd_pci_bus *bus = vmd_device->bus;
855 : :
856 : 5 : spdk_pci_unhook_device(dev);
857 [ - + ]: 5 : TAILQ_REMOVE(&bus->dev_list, vmd_device, tailq);
858 : :
859 : 5 : vmd_dev_free(vmd_device);
860 : 5 : }
861 : :
862 : : static void
863 : 54 : vmd_dev_init(struct vmd_pci_device *dev)
864 : : {
865 : 54 : dev->pci.addr.domain = dev->bus->vmd->domain;
866 : 54 : dev->pci.addr.bus = dev->bus->bus_number;
867 : 54 : dev->pci.addr.dev = dev->devfn;
868 : 54 : dev->pci.addr.func = 0;
869 : 54 : dev->pci.socket_id = spdk_pci_device_get_socket_id(dev->bus->vmd->pci);
870 : 54 : dev->pci.id.vendor_id = dev->header->common.vendor_id;
871 : 54 : dev->pci.id.device_id = dev->header->common.device_id;
872 : 54 : dev->pci.type = "vmd";
873 : 54 : dev->pci.map_bar = vmd_dev_map_bar;
874 : 54 : dev->pci.unmap_bar = vmd_dev_unmap_bar;
875 : 54 : dev->pci.cfg_read = vmd_dev_cfg_read;
876 : 54 : dev->pci.cfg_write = vmd_dev_cfg_write;
877 : 54 : dev->hotplug_capable = false;
878 [ + - ]: 54 : if (dev->pcie_cap != NULL) {
879 : 54 : dev->cached_slot_control = dev->pcie_cap->slot_control;
880 : : }
881 : 54 : }
882 : :
883 : : static int
884 : 6 : vmd_init_end_device(struct vmd_pci_device *dev)
885 : : {
886 : 6 : struct vmd_pci_bus *bus = dev->bus;
887 : : struct vmd_adapter *vmd;
888 : : struct spdk_pci_driver *driver;
889 : 6 : uint8_t bdf[32];
890 : : int rc;
891 : :
892 [ - + ]: 6 : if (!vmd_assign_base_addrs(dev)) {
893 : 0 : SPDK_ERRLOG("Failed to allocate BARs for device: %p\n", dev);
894 : 0 : return -1;
895 : : }
896 : :
897 : 6 : vmd_setup_msix(dev, &bus->vmd->msix_table[0]);
898 : 6 : vmd_dev_init(dev);
899 : :
900 [ + - ]: 6 : if (vmd_is_supported_device(dev)) {
901 : 6 : spdk_pci_addr_fmt(bdf, sizeof(bdf), &dev->pci.addr);
902 [ - + - + ]: 6 : SPDK_INFOLOG(vmd, "Initializing NVMe device at %s\n", bdf);
903 : 6 : dev->pci.parent = dev->bus->vmd->pci;
904 : :
905 : 6 : driver = spdk_pci_nvme_get_driver();
906 [ - + ]: 6 : assert(driver != NULL);
907 : 6 : rc = spdk_pci_hook_device(driver, &dev->pci);
908 [ - + ]: 6 : if (rc != 0) {
909 : 0 : SPDK_ERRLOG("Failed to hook device %s: %s\n", bdf, spdk_strerror(-rc));
910 : 0 : return -1;
911 : : }
912 : :
913 : 6 : vmd = bus->vmd;
914 : 6 : vmd->target[vmd->nvme_count] = dev;
915 : 6 : vmd->nvme_count++;
916 : : }
917 : :
918 : : /* Attach the device to the current bus and assign base addresses */
919 : 6 : TAILQ_INSERT_TAIL(&bus->dev_list, dev, tailq);
920 : 6 : g_end_device_count++;
921 : :
922 : 6 : return 0;
923 : : }
924 : :
925 : : /*
926 : : * Scans a single bus for all devices attached and return a count of
927 : : * how many devices found. In the VMD topology, it is assume there are no multi-
928 : : * function devices. Hence a bus(bridge) will not have multi function with both type
929 : : * 0 and 1 header.
930 : : *
931 : : * The other option for implementing this function is the bus is an int and
932 : : * create a new device PciBridge. PciBridge would inherit from PciDevice with extra fields,
933 : : * sub/pri/sec bus. The input becomes PciPort, bus number and parent_bridge.
934 : : *
935 : : * The bus number is scanned and if a device is found, based on the header_type, create
936 : : * either PciBridge(1) or PciDevice(0).
937 : : *
938 : : * If a PciBridge, assign bus numbers and rescan new bus. The currently PciBridge being
939 : : * scanned becomes the passed in parent_bridge with the new bus number.
940 : : *
941 : : * The linked list becomes list of pciBridges with PciDevices attached.
942 : : *
943 : : * Return count of how many devices found(type1 + type 0 header devices)
944 : : */
945 : : static uint8_t
946 : 66 : vmd_scan_single_bus(struct vmd_pci_bus *bus, struct vmd_pci_device *parent_bridge, bool hotplug)
947 : : {
948 : : /* assuming only single function devices are on the bus */
949 : : struct vmd_pci_device *new_dev;
950 : : union express_slot_capabilities_register slot_cap;
951 : : struct vmd_pci_bus *new_bus;
952 : 66 : uint8_t device_number, dev_cnt = 0;
953 : : uint8_t new_bus_num;
954 : : int rc;
955 : :
956 [ + + ]: 2178 : for (device_number = 0; device_number < 32; device_number++) {
957 : 2112 : new_dev = vmd_alloc_dev(bus, device_number);
958 [ + + ]: 2112 : if (new_dev == NULL) {
959 : 2058 : continue;
960 : : }
961 : :
962 [ + + ]: 54 : if (new_dev->header->common.header_type & PCI_HEADER_TYPE_BRIDGE) {
963 [ - + ]: 48 : if (hotplug) {
964 : 0 : free(new_dev);
965 : 0 : continue;
966 : : }
967 : :
968 : 48 : slot_cap.as_uint32_t = 0;
969 [ + - ]: 48 : if (new_dev->pcie_cap != NULL) {
970 : 48 : slot_cap.as_uint32_t = new_dev->pcie_cap->slot_cap.as_uint32_t;
971 : : }
972 : :
973 : 48 : new_bus_num = vmd_get_next_bus_number(bus->vmd);
974 [ - + ]: 48 : if (new_bus_num == 0xff) {
975 : 0 : vmd_dev_free(new_dev);
976 : 0 : return dev_cnt;
977 : : }
978 : 48 : new_bus = vmd_create_new_bus(bus, new_dev, new_bus_num);
979 [ - + ]: 48 : if (!new_bus) {
980 : 0 : vmd_dev_free(new_dev);
981 : 0 : return dev_cnt;
982 : : }
983 : 48 : new_bus->primary_bus = bus->secondary_bus;
984 : 48 : new_bus->self = new_dev;
985 : 48 : new_dev->bus_object = new_bus;
986 : :
987 [ + + + - ]: 48 : if (slot_cap.bit_field.hotplug_capable && new_dev->pcie_cap != NULL &&
988 [ + - ]: 12 : new_dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
989 : 12 : new_bus->hotplug_buses = vmd_get_hotplug_bus_numbers(new_dev);
990 : 12 : new_bus->subordinate_bus += new_bus->hotplug_buses;
991 : :
992 : : /* Attach hot plug instance if HP is supported */
993 : : /* Hot inserted SSDs can be assigned port bus of sub-ordinate + 1 */
994 [ - + - + ]: 12 : SPDK_INFOLOG(vmd, "hotplug_capable/slot_implemented = "
995 : : "%x:%x\n", slot_cap.bit_field.hotplug_capable,
996 : : new_dev->pcie_cap->express_cap_register.bit_field.slot_implemented);
997 : : }
998 : :
999 : 48 : new_dev->parent_bridge = parent_bridge;
1000 : 48 : new_dev->header->one.primary = new_bus->primary_bus;
1001 : 48 : new_dev->header->one.secondary = new_bus->secondary_bus;
1002 : 48 : new_dev->header->one.subordinate = new_bus->subordinate_bus;
1003 : :
1004 : 48 : vmd_bus_update_bridge_info(new_dev);
1005 : 48 : TAILQ_INSERT_TAIL(&bus->vmd->bus_list, new_bus, tailq);
1006 : :
1007 : 48 : vmd_dev_init(new_dev);
1008 : 48 : dev_cnt++;
1009 : :
1010 [ + + + - ]: 48 : if (slot_cap.bit_field.hotplug_capable && new_dev->pcie_cap != NULL &&
1011 [ + - ]: 12 : new_dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
1012 : 12 : vmd_init_hotplug(new_dev, new_bus);
1013 : : }
1014 : :
1015 : 48 : dev_cnt += vmd_scan_single_bus(new_bus, new_dev, hotplug);
1016 [ + - ]: 48 : if (new_dev->pcie_cap != NULL) {
1017 [ - + ]: 48 : if (new_dev->pcie_cap->express_cap_register.bit_field.device_type == SwitchUpstreamPort) {
1018 : 0 : return dev_cnt;
1019 : : }
1020 : : }
1021 : : } else {
1022 : 6 : rc = vmd_init_end_device(new_dev);
1023 [ - + ]: 6 : if (rc != 0) {
1024 : 0 : vmd_dev_free(new_dev);
1025 : : } else {
1026 : 6 : dev_cnt++;
1027 : : }
1028 : : }
1029 : : }
1030 : :
1031 : 66 : return dev_cnt;
1032 : : }
1033 : :
1034 : : static void
1035 : 54 : vmd_print_pci_info(struct vmd_pci_device *dev)
1036 : : {
1037 [ - + ]: 54 : if (!dev) {
1038 : 0 : return;
1039 : : }
1040 : :
1041 [ + - ]: 54 : if (dev->pcie_cap != NULL) {
1042 [ - + - + ]: 54 : SPDK_INFOLOG(vmd, "PCI DEVICE: [%04X:%04X] type(%x) : %s\n",
1043 : : dev->header->common.vendor_id, dev->header->common.device_id,
1044 : : dev->pcie_cap->express_cap_register.bit_field.device_type,
1045 : : device_type[dev->pcie_cap->express_cap_register.bit_field.device_type]);
1046 : : } else {
1047 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "PCI DEVICE: [%04X:%04X]\n",
1048 : : dev->header->common.vendor_id, dev->header->common.device_id);
1049 : : }
1050 : :
1051 [ - + - + ]: 54 : SPDK_INFOLOG(vmd, "\tDOMAIN:BDF: %04x:%02x:%02x:%x\n", dev->pci.addr.domain,
1052 : : dev->pci.addr.bus, dev->pci.addr.dev, dev->pci.addr.func);
1053 : :
1054 [ + + + - ]: 54 : if (!(dev->header_type & PCI_HEADER_TYPE_BRIDGE) && dev->bus) {
1055 [ - + - + ]: 6 : SPDK_INFOLOG(vmd, "\tbase addr: %x : %p\n",
1056 : : dev->header->zero.BAR[0], (void *)dev->bar[0].vaddr);
1057 : : }
1058 : :
1059 [ + + ]: 54 : if ((dev->header_type & PCI_HEADER_TYPE_BRIDGE)) {
1060 [ - + - + ]: 48 : SPDK_INFOLOG(vmd, "\tPrimary = %d, Secondary = %d, Subordinate = %d\n",
1061 : : dev->header->one.primary, dev->header->one.secondary, dev->header->one.subordinate);
1062 [ + - + + ]: 48 : if (dev->pcie_cap && dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
1063 [ - + - + ]: 24 : SPDK_INFOLOG(vmd, "\tSlot implemented on this device.\n");
1064 [ + + ]: 24 : if (dev->pcie_cap->slot_cap.bit_field.hotplug_capable) {
1065 [ - + - + ]: 12 : SPDK_INFOLOG(vmd, "Device has HOT-PLUG capable slot.\n");
1066 : : }
1067 : : }
1068 : : }
1069 : :
1070 [ + + ]: 54 : if (dev->sn_cap != NULL) {
1071 : 6 : uint8_t *snLow = (uint8_t *)&dev->sn_cap->sn_low;
1072 : 6 : uint8_t *snHi = (uint8_t *)&dev->sn_cap->sn_hi;
1073 : :
1074 [ - + - + ]: 6 : SPDK_INFOLOG(vmd, "\tSN: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n",
1075 : : snHi[3], snHi[2], snHi[1], snHi[0], snLow[3], snLow[2], snLow[1], snLow[0]);
1076 : : }
1077 : : }
1078 : :
1079 : : static void
1080 : 48 : vmd_cache_scan_info(struct vmd_pci_device *dev)
1081 : : {
1082 : : uint32_t reg __attribute__((unused));
1083 : :
1084 [ - + ]: 48 : if (dev->header_type == PCI_HEADER_TYPE_NORMAL) {
1085 : 0 : return;
1086 : : }
1087 : :
1088 [ - + - + ]: 48 : SPDK_INFOLOG(vmd, "vendor/device id:%x:%x\n", dev->header->common.vendor_id,
1089 : : dev->header->common.device_id);
1090 : :
1091 [ + - ]: 48 : if (vmd_device_is_root_port(dev->header)) {
1092 : 48 : dev->header->one.prefetch_base_upper = VMD_UPPER_BASE_SIGNATURE;
1093 : 48 : reg = dev->header->one.prefetch_base_upper;
1094 : 48 : dev->header->one.prefetch_limit_upper = VMD_UPPER_LIMIT_SIGNATURE;
1095 : 48 : reg = dev->header->one.prefetch_limit_upper;
1096 : :
1097 [ - + - + ]: 48 : SPDK_INFOLOG(vmd, "prefetch: %x:%x\n",
1098 : : dev->header->one.prefetch_base_upper,
1099 : : dev->header->one.prefetch_limit_upper);
1100 : : }
1101 : : }
1102 : :
1103 : : static void
1104 : 18 : vmd_reset_root_ports(struct vmd_pci_bus *bus)
1105 : : {
1106 : : volatile struct pci_header *header;
1107 : : uint32_t devfn;
1108 : :
1109 : : /*
1110 : : * The root ports might have been configured by some other driver (e.g. Linux kernel) prior
1111 : : * to loading the SPDK one, so we need to clear it. We need to do it before starting the
1112 : : * scanning process, as it's depth-first, so when initial root ports are scanned, the
1113 : : * latter ones might still be using stale configuration. This can lead to two bridges
1114 : : * having the same secondary/subordinate bus configuration, which, of course, isn't correct.
1115 : : * (Note: this fixed issue #2413.)
1116 : : */
1117 [ + + ]: 594 : for (devfn = 0; devfn < 32; ++devfn) {
1118 [ + + ]: 576 : if (!vmd_bus_device_present(bus, devfn)) {
1119 : 528 : continue;
1120 : : }
1121 : :
1122 : 48 : header = (volatile void *)(bus->vmd->cfg_vaddr +
1123 [ - + ]: 96 : CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
1124 [ + - - + ]: 48 : if (vmd_device_is_root_port(header) && !vmd_device_is_enumerated(header)) {
1125 : 0 : vmd_reset_base_limit_registers(header);
1126 : : }
1127 : : }
1128 : 18 : }
1129 : :
1130 : : static uint8_t
1131 : 18 : vmd_scan_pcibus(struct vmd_pci_bus *bus)
1132 : : {
1133 : : struct vmd_pci_bus *bus_entry;
1134 : : struct vmd_pci_device *dev;
1135 : : uint8_t dev_cnt;
1136 : :
1137 : 18 : vmd_reset_root_ports(bus);
1138 : :
1139 : 18 : g_end_device_count = 0;
1140 : 18 : TAILQ_INSERT_TAIL(&bus->vmd->bus_list, bus, tailq);
1141 : 18 : bus->vmd->next_bus_number = bus->bus_number + 1;
1142 : 18 : dev_cnt = vmd_scan_single_bus(bus, NULL, false);
1143 : :
1144 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "VMD scan found %u devices\n", dev_cnt);
1145 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "VMD scan found %u END DEVICES\n", g_end_device_count);
1146 : :
1147 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "PCIe devices attached to VMD %04x:%02x:%02x:%x...\n",
1148 : : bus->vmd->pci->addr.domain, bus->vmd->pci->addr.bus,
1149 : : bus->vmd->pci->addr.dev, bus->vmd->pci->addr.func);
1150 : :
1151 [ + + ]: 84 : TAILQ_FOREACH(bus_entry, &bus->vmd->bus_list, tailq) {
1152 [ + + ]: 66 : if (bus_entry->self != NULL) {
1153 : 48 : vmd_print_pci_info(bus_entry->self);
1154 : 48 : vmd_cache_scan_info(bus_entry->self);
1155 : : }
1156 : :
1157 [ + + ]: 72 : TAILQ_FOREACH(dev, &bus_entry->dev_list, tailq) {
1158 : 6 : vmd_print_pci_info(dev);
1159 : : }
1160 : : }
1161 : :
1162 : 18 : return dev_cnt;
1163 : : }
1164 : :
1165 : : static int
1166 : 36 : vmd_domain_map_bar(struct vmd_adapter *vmd, uint32_t bar,
1167 : : void **vaddr, uint64_t *paddr, uint64_t *size)
1168 : : {
1169 : 36 : uint64_t unused;
1170 : : int rc;
1171 : :
1172 : 36 : rc = spdk_pci_device_map_bar(vmd->pci, bar, vaddr, &unused, size);
1173 [ - + ]: 36 : if (rc != 0) {
1174 : 0 : return rc;
1175 : : }
1176 : :
1177 : : /* Depending on the IOVA configuration, the physical address of the BAR returned by
1178 : : * spdk_pci_device_map_bar() can be either an actual physical address or a virtual one (if
1179 : : * IOMMU is enabled). Since we do need an actual physical address to fill out the
1180 : : * base/limit registers and the BARs of the devices behind the VMD, read the config space to
1181 : : * get the correct address, regardless of IOVA configuration. */
1182 : 36 : rc = spdk_pci_device_cfg_read(vmd->pci, paddr, sizeof(*paddr),
1183 : 36 : PCI_BAR0_OFFSET + bar * PCI_BAR_SIZE);
1184 [ - + ]: 36 : if (rc != 0) {
1185 : 0 : return rc;
1186 : : }
1187 : :
1188 : 36 : *paddr &= PCI_BAR_MEMORY_ADDR_OFFSET;
1189 : :
1190 : 36 : return 0;
1191 : : }
1192 : :
1193 : : static int
1194 : 18 : vmd_domain_map_bars(struct vmd_adapter *vmd)
1195 : : {
1196 : : int rc;
1197 : :
1198 : 18 : rc = vmd_domain_map_bar(vmd, 0, (void **)&vmd->cfg_vaddr,
1199 : : &vmd->cfgbar, &vmd->cfgbar_size);
1200 [ - + ]: 18 : if (rc != 0) {
1201 : 0 : SPDK_ERRLOG("Failed to map config bar: %s\n", spdk_strerror(-rc));
1202 : 0 : return rc;
1203 : : }
1204 : :
1205 : 18 : rc = vmd_domain_map_bar(vmd, 2, (void **)&vmd->mem_vaddr,
1206 : : &vmd->membar, &vmd->membar_size);
1207 [ - + ]: 18 : if (rc != 0) {
1208 : 0 : SPDK_ERRLOG("Failed to map memory bar: %s\n", spdk_strerror(-rc));
1209 : 0 : return rc;
1210 : : }
1211 : :
1212 : 18 : vmd->physical_addr = vmd->membar;
1213 : 18 : vmd->current_addr_size = vmd->membar_size;
1214 : :
1215 : 18 : return 0;
1216 : : }
1217 : :
1218 : : static void
1219 : 0 : vmd_set_starting_bus_number(struct vmd_adapter *vmd, uint8_t *bus_start,
1220 : : uint8_t *max_bus)
1221 : : {
1222 : 0 : uint32_t vmd_cap = 0, vmd_config = 0;
1223 : : uint8_t bus_restrict_cap, bus_restrictions;
1224 : :
1225 : 0 : spdk_pci_device_cfg_read32(vmd->pci, &vmd_cap, PCI_VMD_VMCAP);
1226 : 0 : spdk_pci_device_cfg_read32(vmd->pci, &vmd_config, PCI_VMD_VMCONFIG);
1227 : :
1228 : 0 : bus_restrict_cap = vmd_cap & 0x1; /* bit 0 */
1229 : 0 : bus_restrictions = (vmd_config >> 8) & 0x3; /* bits 8-9 */
1230 [ # # # # ]: 0 : if ((bus_restrict_cap == 0x1) && (bus_restrictions == 0x1)) {
1231 : 0 : *bus_start = 128;
1232 : 0 : *max_bus = 255;
1233 : : } else {
1234 : 0 : *bus_start = 0;
1235 : 0 : *max_bus = 127;
1236 : : }
1237 : 0 : }
1238 : :
1239 : : static int
1240 : 18 : vmd_enumerate_devices(struct vmd_adapter *vmd)
1241 : : {
1242 : 18 : uint8_t max_bus, bus_start;
1243 : :
1244 : 18 : vmd->vmd_bus.vmd = vmd;
1245 : 18 : vmd->vmd_bus.domain = vmd->pci->addr.domain;
1246 : :
1247 [ - + ]: 18 : if (vmd->pci->id.device_id == PCI_DEVICE_ID_INTEL_VMD_ICX) {
1248 : 0 : vmd_set_starting_bus_number(vmd, &bus_start, &max_bus);
1249 : 0 : vmd->vmd_bus.bus_start = bus_start;
1250 : 0 : vmd->vmd_bus.secondary_bus = vmd->vmd_bus.subordinate_bus = vmd->vmd_bus.bus_start;
1251 : 0 : vmd->vmd_bus.primary_bus = vmd->vmd_bus.bus_number = vmd->vmd_bus.bus_start;
1252 : 0 : vmd->max_pci_bus = max_bus;
1253 : : } else {
1254 : 18 : vmd->vmd_bus.bus_start = 0;
1255 : 18 : vmd->vmd_bus.secondary_bus = vmd->vmd_bus.subordinate_bus = 0;
1256 : 18 : vmd->vmd_bus.primary_bus = vmd->vmd_bus.bus_number = 0;
1257 : 18 : vmd->max_pci_bus = PCI_MAX_BUS_NUMBER;
1258 : : }
1259 : :
1260 : 18 : return vmd_scan_pcibus(&vmd->vmd_bus);
1261 : : }
1262 : :
1263 : : struct vmd_pci_device *
1264 : 5 : vmd_find_device(const struct spdk_pci_addr *addr)
1265 : : {
1266 : : struct vmd_pci_bus *bus;
1267 : : struct vmd_pci_device *dev;
1268 : : uint32_t i;
1269 : :
1270 [ + - ]: 5 : for (i = 0; i < g_vmd_container.count; ++i) {
1271 [ + - ]: 10 : TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
1272 [ + + ]: 10 : if (bus->self) {
1273 [ - + ]: 5 : if (spdk_pci_addr_compare(&bus->self->pci.addr, addr) == 0) {
1274 : 0 : return bus->self;
1275 : : }
1276 : : }
1277 : :
1278 [ + + ]: 10 : TAILQ_FOREACH(dev, &bus->dev_list, tailq) {
1279 [ + - ]: 5 : if (spdk_pci_addr_compare(&dev->pci.addr, addr) == 0) {
1280 : 5 : return dev;
1281 : : }
1282 : : }
1283 : : }
1284 : : }
1285 : :
1286 : 0 : return NULL;
1287 : : }
1288 : :
1289 : : static int
1290 : 18 : vmd_enum_cb(void *ctx, struct spdk_pci_device *pci_dev)
1291 : : {
1292 : 18 : uint32_t cmd_reg = 0;
1293 : 18 : char bdf[32] = {0};
1294 : 18 : struct vmd_container *vmd_c = ctx;
1295 : 18 : struct vmd_adapter *vmd = &vmd_c->vmd[vmd_c->count];
1296 : :
1297 : 18 : spdk_pci_device_cfg_read32(pci_dev, &cmd_reg, 4);
1298 : 18 : cmd_reg |= 0x6; /* PCI bus master/memory enable. */
1299 : 18 : spdk_pci_device_cfg_write32(pci_dev, cmd_reg, 4);
1300 : :
1301 : 18 : spdk_pci_addr_fmt(bdf, sizeof(bdf), &pci_dev->addr);
1302 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "Found a VMD[ %d ] at %s\n", vmd_c->count, bdf);
1303 : :
1304 : : /* map vmd bars */
1305 : 18 : vmd->pci = pci_dev;
1306 : 18 : vmd->vmd_index = vmd_c->count;
1307 [ - + - + ]: 18 : vmd->domain = (pci_dev->addr.bus << 16) | (pci_dev->addr.dev << 8) | pci_dev->addr.func;
1308 : 18 : TAILQ_INIT(&vmd->bus_list);
1309 : :
1310 [ - + ]: 18 : if (vmd_domain_map_bars(vmd) != 0) {
1311 : 0 : return -1;
1312 : : }
1313 : :
1314 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "vmd config bar(%p) vaddr(%p) size(%x)\n",
1315 : : (void *)vmd->cfgbar, (void *)vmd->cfg_vaddr,
1316 : : (uint32_t)vmd->cfgbar_size);
1317 [ - + - + ]: 18 : SPDK_INFOLOG(vmd, "vmd mem bar(%p) vaddr(%p) size(%x)\n",
1318 : : (void *)vmd->membar, (void *)vmd->mem_vaddr,
1319 : : (uint32_t)vmd->membar_size);
1320 : :
1321 : 18 : vmd_c->count++;
1322 : 18 : vmd_enumerate_devices(vmd);
1323 : :
1324 : 18 : return 0;
1325 : : }
1326 : :
1327 : : int
1328 : 0 : spdk_vmd_pci_device_list(struct spdk_pci_addr vmd_addr, struct spdk_pci_device *nvme_list)
1329 : : {
1330 : 0 : int cnt = 0;
1331 : : struct vmd_pci_bus *bus;
1332 : : struct vmd_pci_device *dev;
1333 : : uint32_t i;
1334 : :
1335 [ # # ]: 0 : if (!nvme_list) {
1336 : 0 : return -1;
1337 : : }
1338 : :
1339 [ # # ]: 0 : for (i = 0; i < g_vmd_container.count; ++i) {
1340 [ # # ]: 0 : if (spdk_pci_addr_compare(&vmd_addr, &g_vmd_container.vmd[i].pci->addr) == 0) {
1341 [ # # ]: 0 : TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
1342 [ # # ]: 0 : TAILQ_FOREACH(dev, &bus->dev_list, tailq) {
1343 : 0 : nvme_list[cnt++] = dev->pci;
1344 [ # # ]: 0 : if (!dev->is_hooked) {
1345 : 0 : vmd_dev_init(dev);
1346 : 0 : dev->is_hooked = 1;
1347 : : }
1348 : : }
1349 : : }
1350 : : }
1351 : : }
1352 : :
1353 : 0 : return cnt;
1354 : : }
1355 : :
1356 : : static void
1357 : 0 : vmd_clear_hotplug_status(struct vmd_pci_bus *bus)
1358 : : {
1359 : 0 : struct vmd_pci_device *device = bus->self;
1360 : : uint16_t status __attribute__((unused));
1361 : :
1362 : 0 : status = device->pcie_cap->slot_status.as_uint16_t;
1363 : 0 : device->pcie_cap->slot_status.as_uint16_t = status;
1364 : 0 : status = device->pcie_cap->slot_status.as_uint16_t;
1365 : :
1366 : 0 : status = device->pcie_cap->link_status.as_uint16_t;
1367 : 0 : device->pcie_cap->link_status.as_uint16_t = status;
1368 : 0 : status = device->pcie_cap->link_status.as_uint16_t;
1369 : 0 : }
1370 : :
1371 : : static void
1372 : 0 : vmd_bus_handle_hotplug(struct vmd_pci_bus *bus)
1373 : : {
1374 : : uint8_t num_devices, sleep_count;
1375 : :
1376 [ # # ]: 0 : for (sleep_count = 0; sleep_count < 20; ++sleep_count) {
1377 : : /* Scan until a new device is found */
1378 : 0 : num_devices = vmd_scan_single_bus(bus, bus->self, true);
1379 [ # # ]: 0 : if (num_devices > 0) {
1380 : 0 : break;
1381 : : }
1382 : :
1383 : 0 : spdk_delay_us(200000);
1384 : : }
1385 : :
1386 [ # # ]: 0 : if (num_devices == 0) {
1387 : 0 : SPDK_ERRLOG("Timed out while scanning for hotplugged devices\n");
1388 : : }
1389 : 0 : }
1390 : :
1391 : : static void
1392 : 5 : vmd_remove_device(struct vmd_pci_device *device)
1393 : : {
1394 : 5 : device->pci.internal.pending_removal = true;
1395 : :
1396 : : /* If the device isn't attached, remove it immediately */
1397 [ - + + - ]: 5 : if (!device->pci.internal.attached) {
1398 : 5 : vmd_dev_detach(&device->pci);
1399 : : }
1400 : 5 : }
1401 : :
1402 : : static void
1403 : 0 : vmd_bus_handle_hotremove(struct vmd_pci_bus *bus)
1404 : : {
1405 : : struct vmd_pci_device *device, *tmpdev;
1406 : :
1407 [ # # ]: 0 : TAILQ_FOREACH_SAFE(device, &bus->dev_list, tailq, tmpdev) {
1408 [ # # ]: 0 : if (!vmd_bus_device_present(bus, device->devfn)) {
1409 : 0 : vmd_remove_device(device);
1410 : : }
1411 : : }
1412 : 0 : }
1413 : :
1414 : : int
1415 : 2 : spdk_vmd_hotplug_monitor(void)
1416 : : {
1417 : : struct vmd_pci_bus *bus;
1418 : : struct vmd_pci_device *device;
1419 : 2 : int num_hotplugs = 0;
1420 : : uint32_t i;
1421 : :
1422 [ + + ]: 8 : for (i = 0; i < g_vmd_container.count; ++i) {
1423 [ + + ]: 28 : TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
1424 : 22 : device = bus->self;
1425 [ + + - + : 22 : if (device == NULL || !device->hotplug_capable) {
+ + ]
1426 : 18 : continue;
1427 : : }
1428 : :
1429 [ + - ]: 4 : if (device->pcie_cap->slot_status.bit_field.datalink_state_changed != 1) {
1430 : 4 : continue;
1431 : : }
1432 : :
1433 [ # # ]: 0 : if (device->pcie_cap->link_status.bit_field.datalink_layer_active == 1) {
1434 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "Device hotplug detected on bus "
1435 : : "%"PRIu32"\n", bus->bus_number);
1436 : 0 : vmd_bus_handle_hotplug(bus);
1437 : : } else {
1438 [ # # # # ]: 0 : SPDK_INFOLOG(vmd, "Device hotremove detected on bus "
1439 : : "%"PRIu32"\n", bus->bus_number);
1440 : 0 : vmd_bus_handle_hotremove(bus);
1441 : : }
1442 : :
1443 : 0 : vmd_clear_hotplug_status(bus);
1444 : 0 : num_hotplugs++;
1445 : : }
1446 : : }
1447 : :
1448 : 2 : return num_hotplugs;
1449 : : }
1450 : :
1451 : : int
1452 : 0 : spdk_vmd_remove_device(const struct spdk_pci_addr *addr)
1453 : : {
1454 : : struct vmd_pci_device *device;
1455 : :
1456 : 0 : device = vmd_find_device(addr);
1457 [ # # ]: 0 : if (device == NULL) {
1458 : 0 : return -ENODEV;
1459 : : }
1460 : :
1461 [ # # # # ]: 0 : assert(strcmp(spdk_pci_device_get_type(&device->pci), "vmd") == 0);
1462 : 0 : vmd_remove_device(device);
1463 : :
1464 : 0 : return 0;
1465 : : }
1466 : :
1467 : : int
1468 : 0 : spdk_vmd_rescan(void)
1469 : : {
1470 : : struct vmd_pci_bus *bus;
1471 : : uint32_t i;
1472 : 0 : int rc = 0;
1473 : :
1474 [ # # ]: 0 : for (i = 0; i < g_vmd_container.count; ++i) {
1475 [ # # ]: 0 : TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
1476 : 0 : rc += vmd_scan_single_bus(bus, bus->self, true);
1477 : : }
1478 : : }
1479 : :
1480 : 0 : return rc;
1481 : : }
1482 : :
1483 : : static int
1484 : 393 : vmd_attach_device(const struct spdk_pci_addr *addr)
1485 : : {
1486 : : struct vmd_pci_bus *bus;
1487 : : struct vmd_adapter *vmd;
1488 : : struct vmd_pci_device *dev;
1489 : : uint32_t i;
1490 : : int rc;
1491 : :
1492 : : /* VMD always sets function to zero */
1493 [ - + ]: 393 : if (addr->func != 0) {
1494 : 0 : return -ENODEV;
1495 : : }
1496 : :
1497 [ - + ]: 393 : for (i = 0; i < g_vmd_container.count; ++i) {
1498 : 0 : vmd = &g_vmd_container.vmd[i];
1499 [ # # ]: 0 : if (vmd->domain != addr->domain) {
1500 : 0 : continue;
1501 : : }
1502 : :
1503 [ # # ]: 0 : TAILQ_FOREACH(bus, &vmd->bus_list, tailq) {
1504 [ # # ]: 0 : if (bus->bus_number != addr->bus) {
1505 : 0 : continue;
1506 : : }
1507 : :
1508 : 0 : dev = vmd_alloc_dev(bus, addr->dev);
1509 [ # # ]: 0 : if (dev == NULL) {
1510 : 0 : return -ENODEV;
1511 : : }
1512 : :
1513 : : /* Only allow attaching endpoint devices */
1514 [ # # ]: 0 : if (dev->header->common.header_type & PCI_HEADER_TYPE_BRIDGE) {
1515 : 0 : free(dev);
1516 : 0 : return -ENODEV;
1517 : : }
1518 : :
1519 : 0 : rc = vmd_init_end_device(dev);
1520 [ # # ]: 0 : if (rc != 0) {
1521 : 0 : free(dev);
1522 : 0 : return -ENODEV;
1523 : : }
1524 : :
1525 : 0 : return 0;
1526 : : }
1527 : : }
1528 : :
1529 : 393 : return -ENODEV;
1530 : : }
1531 : :
1532 : : static void
1533 : 5 : vmd_detach_device(struct spdk_pci_device *pci_dev)
1534 : : {
1535 : 5 : struct vmd_pci_device *dev = SPDK_CONTAINEROF(pci_dev, struct vmd_pci_device, pci);
1536 : :
1537 [ - + - + ]: 5 : assert(strcmp(spdk_pci_device_get_type(pci_dev), "vmd") == 0);
1538 [ - + ]: 5 : assert(vmd_find_device(&pci_dev->addr) != NULL);
1539 : :
1540 : 5 : vmd_remove_device(dev);
1541 : 5 : }
1542 : :
1543 : : static struct spdk_pci_device_provider g_vmd_device_provider = {
1544 : : .name = "vmd",
1545 : : .attach_cb = vmd_attach_device,
1546 : : .detach_cb = vmd_detach_device,
1547 : : };
1548 : :
1549 : 2957 : SPDK_PCI_REGISTER_DEVICE_PROVIDER(vmd, &g_vmd_device_provider);
1550 : :
1551 : : int
1552 : 6 : spdk_vmd_init(void)
1553 : : {
1554 : 6 : return spdk_pci_enumerate(spdk_pci_vmd_get_driver(), vmd_enum_cb, &g_vmd_container);
1555 : : }
1556 : :
1557 : : void
1558 : 2385 : spdk_vmd_fini(void)
1559 : : {
1560 : : uint32_t i;
1561 : :
1562 [ + + ]: 2403 : for (i = 0; i < g_vmd_container.count; ++i) {
1563 : 18 : spdk_pci_device_detach(g_vmd_container.vmd[i].pci);
1564 : : }
1565 : 2385 : }
1566 : :
1567 : 2957 : SPDK_LOG_REGISTER_COMPONENT(vmd)
|