LCOV - code coverage report
Current view: top level - spdk/lib/vmd - vmd.c (source / functions) Hit Total Coverage
Test: Combined Lines: 9 751 1.2 %
Date: 2024-07-14 08:07:38 Functions: 4 62 6.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 3 572 0.5 %

           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                 :          0 : vmd_is_valid_cfg_addr(struct vmd_pci_bus *bus, uint64_t addr)
      40                 :            : {
      41         [ #  # ]:          0 :         return addr >= (uint64_t)bus->vmd->cfg_vaddr &&
      42         [ #  # ]:          0 :                addr < bus->vmd->cfgbar_size + (uint64_t)bus->vmd->cfg_vaddr;
      43                 :            : }
      44                 :            : 
      45                 :            : static void
      46                 :          0 : 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         [ #  # ]:          0 :         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                 :          0 : }
      59                 :            : 
      60                 :            : static bool
      61                 :          0 : vmd_device_is_enumerated(volatile struct pci_header *header)
      62                 :            : {
      63         [ #  # ]:          0 :         return header->one.prefetch_base_upper == VMD_UPPER_BASE_SIGNATURE &&
      64         [ #  # ]:          0 :                header->one.prefetch_limit_upper == VMD_UPPER_LIMIT_SIGNATURE;
      65                 :            : }
      66                 :            : 
      67                 :            : static bool
      68                 :          0 : vmd_device_is_root_port(volatile struct pci_header *header)
      69                 :            : {
      70         [ #  # ]:          0 :         return header->common.vendor_id == SPDK_PCI_VID_INTEL &&
      71         [ #  # ]:          0 :                (header->common.device_id == PCI_ROOT_PORT_A_INTEL_SKX ||
      72         [ #  # ]:          0 :                 header->common.device_id == PCI_ROOT_PORT_B_INTEL_SKX ||
      73         [ #  # ]:          0 :                 header->common.device_id == PCI_ROOT_PORT_C_INTEL_SKX ||
      74         [ #  # ]:          0 :                 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                 :          0 : vmd_hotplug_coalesce_regions(struct vmd_hot_plug *hp)
      83                 :            : {
      84                 :            :         struct pci_mem_mgr *region, *prev;
      85                 :            : 
      86                 :            :         do {
      87                 :          0 :                 prev = NULL;
      88         [ #  # ]:          0 :                 TAILQ_FOREACH(region, &hp->free_mem_queue, tailq) {
      89   [ #  #  #  # ]:          0 :                         if (prev != NULL && (prev->addr + prev->size == region->addr)) {
      90                 :          0 :                                 break;
      91                 :            :                         }
      92                 :            : 
      93                 :          0 :                         prev = region;
      94                 :            :                 }
      95                 :            : 
      96         [ #  # ]:          0 :                 if (region != NULL) {
      97                 :          0 :                         prev->size += region->size;
      98         [ #  # ]:          0 :                         TAILQ_REMOVE(&hp->free_mem_queue, region, tailq);
      99                 :          0 :                         TAILQ_INSERT_TAIL(&hp->unused_mem_queue, region, tailq);
     100                 :            :                 }
     101         [ #  # ]:          0 :         } while (region != NULL);
     102                 :          0 : }
     103                 :            : 
     104                 :            : static void
     105                 :          0 : vmd_hotplug_free_region(struct vmd_hot_plug *hp, struct pci_mem_mgr *region)
     106                 :            : {
     107                 :          0 :         struct pci_mem_mgr *current, *prev = NULL;
     108                 :            : 
     109   [ #  #  #  # ]:          0 :         assert(region->addr >= hp->bar.start && region->addr < hp->bar.start + hp->bar.size);
     110                 :            : 
     111         [ #  # ]:          0 :         TAILQ_FOREACH(current, &hp->free_mem_queue, tailq) {
     112         [ #  # ]:          0 :                 if (current->addr > region->addr) {
     113                 :          0 :                         break;
     114                 :            :                 }
     115                 :            : 
     116                 :          0 :                 prev = current;
     117                 :            :         }
     118                 :            : 
     119         [ #  # ]:          0 :         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         [ #  # ]:          0 :                 TAILQ_INSERT_HEAD(&hp->free_mem_queue, region, tailq);
     125                 :            :         }
     126                 :            : 
     127                 :          0 :         vmd_hotplug_coalesce_regions(hp);
     128                 :          0 : }
     129                 :            : 
     130                 :            : static void
     131                 :          0 : vmd_hotplug_free_addr(struct vmd_hot_plug *hp, uint64_t addr)
     132                 :            : {
     133                 :            :         struct pci_mem_mgr *region;
     134                 :            : 
     135         [ #  # ]:          0 :         TAILQ_FOREACH(region, &hp->alloc_mem_queue, tailq) {
     136         [ #  # ]:          0 :                 if (region->addr == addr) {
     137                 :          0 :                         break;
     138                 :            :                 }
     139                 :            :         }
     140                 :            : 
     141         [ #  # ]:          0 :         assert(region != NULL);
     142         [ #  # ]:          0 :         TAILQ_REMOVE(&hp->alloc_mem_queue, region, tailq);
     143                 :            : 
     144                 :          0 :         vmd_hotplug_free_region(hp, region);
     145                 :          0 : }
     146                 :            : 
     147                 :            : static uint64_t
     148                 :          0 : vmd_hotplug_allocate_base_addr(struct vmd_hot_plug *hp, uint32_t size)
     149                 :            : {
     150                 :          0 :         struct pci_mem_mgr *region = NULL, *free_region;
     151                 :            : 
     152         [ #  # ]:          0 :         TAILQ_FOREACH(region, &hp->free_mem_queue, tailq) {
     153         [ #  # ]:          0 :                 if (region->size >= size) {
     154                 :          0 :                         break;
     155                 :            :                 }
     156                 :            :         }
     157                 :            : 
     158         [ #  # ]:          0 :         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         [ #  # ]:          0 :         TAILQ_REMOVE(&hp->free_mem_queue, region, tailq);
     165         [ #  # ]:          0 :         if (size < region->size) {
     166                 :          0 :                 free_region = TAILQ_FIRST(&hp->unused_mem_queue);
     167         [ #  # ]:          0 :                 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         [ #  # ]:          0 :                         TAILQ_REMOVE(&hp->unused_mem_queue, free_region, tailq);
     172                 :          0 :                         free_region->size = region->size - size;
     173                 :          0 :                         free_region->addr = region->addr + size;
     174                 :          0 :                         region->size = size;
     175                 :          0 :                         vmd_hotplug_free_region(hp, free_region);
     176                 :            :                 }
     177                 :            :         }
     178                 :            : 
     179                 :          0 :         TAILQ_INSERT_TAIL(&hp->alloc_mem_queue, region, tailq);
     180                 :            : 
     181                 :          0 :         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                 :          0 : vmd_is_end_device(struct vmd_pci_device *dev)
     235                 :            : {
     236   [ #  #  #  # ]:          0 :         return (dev && dev->header) &&
     237         [ #  # ]:          0 :                ((dev->header->common.header_type & ~PCI_MULTI_FUNCTION) == PCI_HEADER_TYPE_NORMAL);
     238                 :            : }
     239                 :            : 
     240                 :            : static void
     241                 :          0 : 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   [ #  #  #  # ]:          0 :         if (base == 0 ||  limit == 0) {
     247                 :          0 :                 return;
     248                 :            :         }
     249                 :            : 
     250         [ #  # ]:          0 :         if (dev->header->common.header_type == PCI_HEADER_TYPE_BRIDGE) {
     251                 :          0 :                 bus = dev->bus_object;
     252                 :            :         } else {
     253                 :          0 :                 bus = dev->parent;
     254                 :            :         }
     255                 :            : 
     256                 :          0 :         bridge = bus->self;
     257   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "base:limit = %x:%x\n", bridge->header->one.mem_base,
     258                 :            :                      bridge->header->one.mem_limit);
     259                 :            : 
     260         [ #  # ]:          0 :         if (dev->bus->vmd->scan_completed) {
     261                 :          0 :                 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                 :          0 : vmd_get_base_addr(struct vmd_pci_device *dev, uint32_t index, uint32_t size)
     284                 :            : {
     285                 :          0 :         struct vmd_pci_bus *bus = dev->parent;
     286                 :            : 
     287         [ #  # ]:          0 :         if (dev->header_type == PCI_HEADER_TYPE_BRIDGE) {
     288                 :          0 :                 return dev->header->zero.BAR[index] & ~0xf;
     289                 :            :         } else {
     290   [ #  #  #  # ]:          0 :                 if (bus->self->hotplug_capable) {
     291                 :          0 :                         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                 :          0 : vmd_assign_base_addrs(struct vmd_pci_device *dev)
     300                 :            : {
     301                 :          0 :         uint16_t mem_base = 0, mem_limit = 0;
     302                 :          0 :         unsigned char mem_attr = 0;
     303                 :            :         int last;
     304                 :          0 :         struct vmd_adapter *vmd = NULL;
     305                 :          0 :         bool ret_val = false;
     306                 :            :         uint32_t bar_value;
     307                 :            :         uint32_t table_offset;
     308                 :            : 
     309   [ #  #  #  # ]:          0 :         if (dev && dev->bus) {
     310                 :          0 :                 vmd = dev->bus->vmd;
     311                 :            :         }
     312                 :            : 
     313         [ #  # ]:          0 :         if (!vmd) {
     314                 :          0 :                 return 0;
     315                 :            :         }
     316                 :            : 
     317                 :          0 :         vmd_align_base_addrs(vmd, ONE_MB);
     318                 :            : 
     319         [ #  # ]:          0 :         last = dev->header_type ? 2 : 6;
     320         [ #  # ]:          0 :         for (int i = 0; i < last; i++) {
     321                 :          0 :                 bar_value = dev->header->zero.BAR[i];
     322                 :          0 :                 dev->header->zero.BAR[i] = ~(0U);
     323                 :          0 :                 dev->bar[i].size = dev->header->zero.BAR[i];
     324                 :          0 :                 dev->header->zero.BAR[i] = bar_value;
     325                 :            : 
     326   [ #  #  #  # ]:          0 :                 if (dev->bar[i].size == ~(0U) || dev->bar[i].size == 0  ||
     327         [ #  # ]:          0 :                     dev->header->zero.BAR[i] & 1) {
     328                 :          0 :                         dev->bar[i].size = 0;
     329                 :          0 :                         continue;
     330                 :            :                 }
     331                 :          0 :                 mem_attr = dev->bar[i].size & PCI_BASE_ADDR_MASK;
     332                 :          0 :                 dev->bar[i].size = TWOS_COMPLEMENT(dev->bar[i].size & PCI_BASE_ADDR_MASK);
     333                 :            : 
     334         [ #  # ]:          0 :                 if (vmd->scan_completed) {
     335                 :          0 :                         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                 :          0 :                 dev->header->zero.BAR[i] = (uint32_t)dev->bar[i].start;
     341                 :            : 
     342         [ #  # ]:          0 :                 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                 :          0 :                 dev->bar[i].vaddr = ((uint64_t)vmd->mem_vaddr + (dev->bar[i].start - vmd->membar));
     350                 :          0 :                 mem_limit = BRIDGE_BASEREG(dev->header->zero.BAR[i]) +
     351                 :          0 :                             BRIDGE_BASEREG(dev->bar[i].size - 1);
     352         [ #  # ]:          0 :                 if (!mem_base) {
     353                 :          0 :                         mem_base = BRIDGE_BASEREG(dev->header->zero.BAR[i]);
     354                 :            :                 }
     355                 :            : 
     356                 :          0 :                 ret_val = true;
     357                 :            : 
     358         [ #  # ]:          0 :                 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                 :          0 :         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                 :          0 :         { uint16_t cmd = dev->header->zero.command; (void)cmd; }
     373                 :            : 
     374   [ #  #  #  # ]:          0 :         if (dev->msix_cap && ret_val) {
     375                 :          0 :                 table_offset = ((volatile struct pci_msix_cap *)dev->msix_cap)->msix_table_offset;
     376         [ #  # ]:          0 :                 if (dev->bar[table_offset & 0x3].vaddr) {
     377                 :          0 :                         dev->msix_table = (volatile struct pci_msix_table_entry *)
     378                 :          0 :                                           (dev->bar[table_offset & 0x3].vaddr + (table_offset & 0xfff8));
     379                 :            :                 }
     380                 :            :         }
     381                 :            : 
     382   [ #  #  #  # ]:          0 :         if (ret_val && vmd_is_end_device(dev)) {
     383                 :          0 :                 vmd_update_base_limit_register(dev, mem_base, mem_limit);
     384                 :            :         }
     385                 :            : 
     386                 :          0 :         return ret_val;
     387                 :            : }
     388                 :            : 
     389                 :            : static void
     390                 :          0 : 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                 :          0 :         config_space = (volatile uint8_t *)dev->header;
     398         [ #  # ]:          0 :         if ((dev->header->common.status  & PCI_CAPABILITIES_LIST) == 0) {
     399                 :          0 :                 return;
     400                 :            :         }
     401                 :            : 
     402                 :          0 :         capabilities_offset = dev->header->zero.cap_pointer;
     403         [ #  # ]:          0 :         if (dev->header->common.header_type & PCI_HEADER_TYPE_BRIDGE) {
     404                 :          0 :                 capabilities_offset = dev->header->one.cap_pointer;
     405                 :            :         }
     406                 :            : 
     407         [ #  # ]:          0 :         while (capabilities_offset > 0) {
     408                 :          0 :                 capabilities_hdr = (struct pci_capabilities_header *)
     409                 :          0 :                                    &config_space[capabilities_offset];
     410   [ #  #  #  # ]:          0 :                 switch (capabilities_hdr->capability_id) {
     411                 :          0 :                 case CAPABILITY_ID_PCI_EXPRESS:
     412                 :          0 :                         dev->pcie_cap = (volatile struct pci_express_cap *)(capabilities_hdr);
     413                 :          0 :                         break;
     414                 :            : 
     415                 :          0 :                 case CAPABILITY_ID_MSI:
     416                 :          0 :                         dev->msi_cap = (volatile struct pci_msi_cap *)capabilities_hdr;
     417                 :          0 :                         break;
     418                 :            : 
     419                 :          0 :                 case CAPABILITY_ID_MSIX:
     420                 :          0 :                         dev->msix_cap = (volatile struct pci_msix_capability *)capabilities_hdr;
     421                 :          0 :                         dev->msix_table_size = dev->msix_cap->message_control.bit.table_size + 1;
     422                 :          0 :                         break;
     423                 :            : 
     424                 :          0 :                 default:
     425                 :          0 :                         break;
     426                 :            :                 }
     427                 :          0 :                 capabilities_offset = capabilities_hdr->next;
     428                 :            :         }
     429                 :            : }
     430                 :            : 
     431                 :            : static volatile struct pci_enhanced_capability_header *
     432                 :          0 : vmd_get_enhanced_capabilities(struct vmd_pci_device *dev, uint16_t capability_id)
     433                 :            : {
     434                 :            :         uint8_t *data;
     435                 :          0 :         uint16_t cap_offset = EXTENDED_CAPABILITY_OFFSET;
     436                 :          0 :         volatile struct pci_enhanced_capability_header *cap_hdr = NULL;
     437                 :            : 
     438                 :          0 :         data = (uint8_t *)dev->header;
     439         [ #  # ]:          0 :         while (cap_offset >= EXTENDED_CAPABILITY_OFFSET) {
     440                 :          0 :                 cap_hdr = (volatile struct pci_enhanced_capability_header *) &data[cap_offset];
     441         [ #  # ]:          0 :                 if (cap_hdr->capability_id == capability_id) {
     442                 :          0 :                         return cap_hdr;
     443                 :            :                 }
     444                 :          0 :                 cap_offset = cap_hdr->next;
     445   [ #  #  #  # ]:          0 :                 if (cap_offset == 0 || cap_offset < EXTENDED_CAPABILITY_OFFSET) {
     446                 :            :                         break;
     447                 :            :                 }
     448                 :            :         }
     449                 :            : 
     450                 :          0 :         return NULL;
     451                 :            : }
     452                 :            : 
     453                 :            : static void
     454                 :          0 : 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                 :          0 :         dev->header->common.command |= (BUS_MASTER_ENABLE | MEMORY_SPACE_ENABLE);
     461                 :          0 :         { uint16_t cmd = dev->header->common.command; (void)cmd; }
     462                 :            : 
     463                 :          0 :         vmd_get_device_capabilities(dev);
     464                 :          0 :         dev->sn_cap = (struct serial_number_capability *)vmd_get_enhanced_capabilities(dev,
     465                 :            :                         DEVICE_SERIAL_NUMBER_CAP_ID);
     466                 :          0 : }
     467                 :            : 
     468                 :            : static void
     469                 :          0 : vmd_update_scan_info(struct vmd_pci_device *dev)
     470                 :            : {
     471                 :          0 :         struct vmd_adapter *vmd_adapter = dev->bus->vmd;
     472                 :            : 
     473         [ #  # ]:          0 :         if (vmd_adapter->root_port_updated) {
     474                 :          0 :                 return;
     475                 :            :         }
     476                 :            : 
     477         [ #  # ]:          0 :         if (dev->header_type == PCI_HEADER_TYPE_NORMAL) {
     478                 :          0 :                 return;
     479                 :            :         }
     480                 :            : 
     481         [ #  # ]:          0 :         if (vmd_device_is_root_port(dev->header)) {
     482                 :          0 :                 vmd_adapter->root_port_updated = 1;
     483   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vmd, "root_port_updated = %d\n",
     484                 :            :                              vmd_adapter->root_port_updated);
     485   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vmd, "upper:limit = %x : %x\n",
     486                 :            :                              dev->header->one.prefetch_base_upper,
     487                 :            :                              dev->header->one.prefetch_limit_upper);
     488         [ #  # ]:          0 :                 if (vmd_device_is_enumerated(dev->header)) {
     489                 :          0 :                         vmd_adapter->scan_completed = 1;
     490   [ #  #  #  # ]:          0 :                         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                 :          0 : vmd_init_hotplug(struct vmd_pci_device *dev, struct vmd_pci_bus *bus)
     533                 :            : {
     534                 :          0 :         struct vmd_adapter *vmd = bus->vmd;
     535                 :          0 :         struct vmd_hot_plug *hp = &dev->hp;
     536                 :            :         size_t mem_id;
     537                 :            : 
     538                 :          0 :         dev->hotplug_capable = true;
     539                 :          0 :         hp->bar.size = 1 << 20;
     540                 :            : 
     541         [ #  # ]:          0 :         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                 :          0 :                 hp->bar.start = (uint64_t)bus->self->header->one.mem_base << 16;
     548                 :            :         }
     549                 :            : 
     550                 :          0 :         hp->bar.vaddr = (uint64_t)vmd->mem_vaddr + (hp->bar.start - vmd->membar);
     551                 :            : 
     552                 :          0 :         TAILQ_INIT(&hp->free_mem_queue);
     553                 :          0 :         TAILQ_INIT(&hp->unused_mem_queue);
     554                 :          0 :         TAILQ_INIT(&hp->alloc_mem_queue);
     555                 :            : 
     556                 :          0 :         hp->mem[0].size = hp->bar.size;
     557                 :          0 :         hp->mem[0].addr = hp->bar.start;
     558                 :            : 
     559                 :          0 :         TAILQ_INSERT_TAIL(&hp->free_mem_queue, &hp->mem[0], tailq);
     560                 :            : 
     561         [ #  # ]:          0 :         for (mem_id = 1; mem_id < ADDR_ELEM_COUNT; ++mem_id) {
     562                 :          0 :                 TAILQ_INSERT_TAIL(&hp->unused_mem_queue, &hp->mem[mem_id], tailq);
     563                 :            :         }
     564                 :            : 
     565   [ #  #  #  # ]:          0 :         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                 :          0 : }
     568                 :            : 
     569                 :            : static bool
     570                 :          0 : vmd_bus_device_present(struct vmd_pci_bus *bus, uint32_t devfn)
     571                 :            : {
     572                 :            :         volatile struct pci_header *header;
     573                 :            : 
     574                 :          0 :         header = (volatile struct pci_header *)(bus->vmd->cfg_vaddr +
     575         [ #  # ]:          0 :                                                 CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
     576         [ #  # ]:          0 :         if (!vmd_is_valid_cfg_addr(bus, (uint64_t)header)) {
     577                 :          0 :                 return false;
     578                 :            :         }
     579                 :            : 
     580   [ #  #  #  # ]:          0 :         if (header->common.vendor_id == PCI_INVALID_VENDORID || header->common.vendor_id == 0x0) {
     581                 :          0 :                 return false;
     582                 :            :         }
     583                 :            : 
     584                 :          0 :         return true;
     585                 :            : }
     586                 :            : 
     587                 :            : static struct vmd_pci_device *
     588                 :          0 : vmd_alloc_dev(struct vmd_pci_bus *bus, uint32_t devfn)
     589                 :            : {
     590                 :          0 :         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         [ #  # ]:          0 :         TAILQ_FOREACH(dev, &bus->dev_list, tailq) {
     597         [ #  # ]:          0 :                 if (dev->devfn == devfn) {
     598                 :          0 :                         return NULL;
     599                 :            :                 }
     600                 :            :         }
     601                 :            : 
     602         [ #  # ]:          0 :         if (!vmd_bus_device_present(bus, devfn)) {
     603                 :          0 :                 return NULL;
     604                 :            :         }
     605                 :            : 
     606                 :          0 :         header = (struct pci_header * volatile)(bus->vmd->cfg_vaddr +
     607         [ #  # ]:          0 :                                                 CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
     608                 :            : 
     609   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "PCI device found: %04x:%04x ***\n",
     610                 :            :                      header->common.vendor_id, header->common.device_id);
     611                 :            : 
     612                 :          0 :         dev = calloc(1, sizeof(*dev));
     613         [ #  # ]:          0 :         if (!dev) {
     614                 :          0 :                 return NULL;
     615                 :            :         }
     616                 :            : 
     617                 :          0 :         dev->header = header;
     618                 :          0 :         dev->vid = dev->header->common.vendor_id;
     619                 :          0 :         dev->did = dev->header->common.device_id;
     620                 :          0 :         dev->bus = bus;
     621                 :          0 :         dev->parent = bus;
     622                 :          0 :         dev->devfn = devfn;
     623                 :          0 :         header_type = dev->header->common.header_type;
     624                 :          0 :         rev_class = dev->header->common.rev_class;
     625                 :          0 :         dev->class = rev_class >> 8;
     626                 :          0 :         dev->header_type = header_type & 0x7;
     627                 :            : 
     628         [ #  # ]:          0 :         if (header_type == PCI_HEADER_TYPE_BRIDGE) {
     629                 :          0 :                 vmd_update_scan_info(dev);
     630         [ #  # ]:          0 :                 if (!dev->bus->vmd->scan_completed) {
     631                 :          0 :                         vmd_reset_base_limit_registers(dev->header);
     632                 :            :                 }
     633                 :            :         }
     634                 :            : 
     635                 :          0 :         vmd_read_config_space(dev);
     636                 :            : 
     637                 :          0 :         return dev;
     638                 :            : }
     639                 :            : 
     640                 :            : static struct vmd_pci_bus *
     641                 :          0 : 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                 :          0 :         new_bus = calloc(1, sizeof(*new_bus));
     646         [ #  # ]:          0 :         if (!new_bus) {
     647                 :          0 :                 return NULL;
     648                 :            :         }
     649                 :            : 
     650                 :          0 :         new_bus->parent = parent;
     651                 :          0 :         new_bus->domain = parent->domain;
     652                 :          0 :         new_bus->bus_number = bus_number;
     653                 :          0 :         new_bus->secondary_bus = new_bus->subordinate_bus = bus_number;
     654                 :          0 :         new_bus->self = bridge;
     655                 :          0 :         new_bus->vmd = parent->vmd;
     656                 :          0 :         new_bus->config_bus_number = new_bus->bus_number - new_bus->vmd->vmd_bus.bus_start;
     657                 :          0 :         TAILQ_INIT(&new_bus->dev_list);
     658                 :            : 
     659                 :          0 :         bridge->subordinate = new_bus;
     660                 :            : 
     661                 :          0 :         bridge->pci.addr.bus = new_bus->bus_number;
     662                 :          0 :         bridge->pci.addr.dev = bridge->devfn;
     663                 :          0 :         bridge->pci.addr.func = 0;
     664                 :          0 :         bridge->pci.addr.domain = parent->vmd->pci->addr.domain;
     665                 :            : 
     666                 :          0 :         return new_bus;
     667                 :            : }
     668                 :            : 
     669                 :            : static uint8_t
     670                 :          0 : vmd_get_next_bus_number(struct vmd_adapter *vmd)
     671                 :            : {
     672                 :          0 :         uint8_t bus = 0xff;
     673                 :            : 
     674         [ #  # ]:          0 :         if ((vmd->next_bus_number + 1) < vmd->max_pci_bus) {
     675                 :          0 :                 bus = vmd->next_bus_number;
     676                 :          0 :                 vmd->next_bus_number++;
     677                 :            :         }
     678                 :            : 
     679                 :          0 :         return bus;
     680                 :            : }
     681                 :            : 
     682                 :            : static uint8_t
     683                 :          0 : vmd_get_hotplug_bus_numbers(struct vmd_pci_device *dev)
     684                 :            : {
     685                 :          0 :         uint8_t bus_number = 0xff;
     686                 :            : 
     687   [ #  #  #  #  :          0 :         if (dev && dev->bus && dev->bus->vmd &&
                   #  # ]
     688         [ #  # ]:          0 :             ((dev->bus->vmd->next_bus_number + RESERVED_HOTPLUG_BUSES) < dev->bus->vmd->max_pci_bus)) {
     689                 :          0 :                 bus_number = RESERVED_HOTPLUG_BUSES;
     690                 :          0 :                 dev->bus->vmd->next_bus_number += RESERVED_HOTPLUG_BUSES;
     691                 :            :         }
     692                 :            : 
     693                 :          0 :         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                 :          0 : vmd_setup_msix(struct vmd_pci_device *dev, volatile struct pci_msix_table_entry *vmdEntry)
     729                 :            : {
     730                 :            :         int entry;
     731                 :            : 
     732   [ #  #  #  #  :          0 :         if (!dev || !vmdEntry || !dev->msix_cap) {
                   #  # ]
     733                 :          0 :                 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                 :          0 : vmd_bus_update_bridge_info(struct vmd_pci_device *bridge)
     749                 :            : {
     750                 :            :         /* Update the subordinate bus of all bridges above this bridge */
     751                 :          0 :         volatile struct vmd_pci_device *dev = bridge;
     752                 :            :         uint8_t subordinate_bus;
     753                 :            : 
     754         [ #  # ]:          0 :         if (!dev) {
     755                 :          0 :                 return;
     756                 :            :         }
     757                 :          0 :         subordinate_bus = bridge->header->one.subordinate;
     758         [ #  # ]:          0 :         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                 :          0 : vmd_is_supported_device(struct vmd_pci_device *dev)
     769                 :            : {
     770                 :          0 :         return dev->class == PCI_CLASS_STORAGE_EXPRESS;
     771                 :            : }
     772                 :            : 
     773                 :            : static int
     774                 :          0 : 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                 :          0 :         struct vmd_pci_device *dev = SPDK_CONTAINEROF(pci_dev, struct vmd_pci_device, pci);
     778                 :            : 
     779                 :          0 :         *size = dev->bar[bar].size;
     780                 :          0 :         *phys_addr = dev->bar[bar].start;
     781                 :          0 :         *mapped_addr = (void *)dev->bar[bar].vaddr;
     782                 :            : 
     783                 :          0 :         return 0;
     784                 :            : }
     785                 :            : 
     786                 :            : static int
     787                 :          0 : vmd_dev_unmap_bar(struct spdk_pci_device *_dev, uint32_t bar, void *addr)
     788                 :            : {
     789                 :          0 :         return 0;
     790                 :            : }
     791                 :            : 
     792                 :            : static int
     793                 :          0 : vmd_dev_cfg_read(struct spdk_pci_device *_dev, void *value, uint32_t len,
     794                 :            :                  uint32_t offset)
     795                 :            : {
     796                 :          0 :         struct vmd_pci_device *dev = SPDK_CONTAINEROF(_dev, struct vmd_pci_device, pci);
     797                 :          0 :         volatile uint8_t *src = (volatile uint8_t *)dev->header;
     798                 :          0 :         uint8_t *dst = value;
     799                 :            :         size_t i;
     800                 :            : 
     801         [ #  # ]:          0 :         if (len + offset > PCI_MAX_CFG_SIZE) {
     802                 :          0 :                 return -1;
     803                 :            :         }
     804                 :            : 
     805         [ #  # ]:          0 :         for (i = 0; i < len; ++i) {
     806                 :          0 :                 dst[i] = src[offset + i];
     807                 :            :         }
     808                 :            : 
     809                 :          0 :         return 0;
     810                 :            : }
     811                 :            : 
     812                 :            : static int
     813                 :          0 : vmd_dev_cfg_write(struct spdk_pci_device *_dev,  void *value,
     814                 :            :                   uint32_t len, uint32_t offset)
     815                 :            : {
     816                 :          0 :         struct vmd_pci_device *dev = SPDK_CONTAINEROF(_dev, struct vmd_pci_device, pci);
     817                 :          0 :         volatile uint8_t *dst = (volatile uint8_t *)dev->header;
     818                 :          0 :         uint8_t *src = value;
     819                 :            :         size_t i;
     820                 :            : 
     821         [ #  # ]:          0 :         if ((len + offset) > PCI_MAX_CFG_SIZE) {
     822                 :          0 :                 return -1;
     823                 :            :         }
     824                 :            : 
     825         [ #  # ]:          0 :         for (i = 0; i < len; ++i) {
     826                 :          0 :                 dst[offset + i] = src[i];
     827                 :            :         }
     828                 :            : 
     829                 :          0 :         return 0;
     830                 :            : }
     831                 :            : 
     832                 :            : static void
     833                 :          0 : vmd_dev_free(struct vmd_pci_device *dev)
     834                 :            : {
     835                 :          0 :         struct vmd_pci_device *bus_device = dev->bus->self;
     836         [ #  # ]:          0 :         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   [ #  #  #  #  :          0 :         if (bus_device && bus_device->hotplug_capable) {
                   #  # ]
     840         [ #  # ]:          0 :                 for (i = 0; i < num_bars; ++i) {
     841         [ #  # ]:          0 :                         if (dev->bar[i].start != 0) {
     842                 :          0 :                                 vmd_hotplug_free_addr(&bus_device->hp, dev->bar[i].start);
     843                 :            :                         }
     844                 :            :                 }
     845                 :            :         }
     846                 :            : 
     847                 :          0 :         free(dev);
     848                 :          0 : }
     849                 :            : 
     850                 :            : static void
     851                 :          0 : vmd_dev_detach(struct spdk_pci_device *dev)
     852                 :            : {
     853                 :          0 :         struct vmd_pci_device *vmd_device = (struct vmd_pci_device *)dev;
     854                 :          0 :         struct vmd_pci_bus *bus = vmd_device->bus;
     855                 :            : 
     856                 :          0 :         spdk_pci_unhook_device(dev);
     857         [ #  # ]:          0 :         TAILQ_REMOVE(&bus->dev_list, vmd_device, tailq);
     858                 :            : 
     859                 :          0 :         vmd_dev_free(vmd_device);
     860                 :          0 : }
     861                 :            : 
     862                 :            : static void
     863                 :          0 : vmd_dev_init(struct vmd_pci_device *dev)
     864                 :            : {
     865                 :          0 :         dev->pci.addr.domain = dev->bus->vmd->domain;
     866                 :          0 :         dev->pci.addr.bus = dev->bus->bus_number;
     867                 :          0 :         dev->pci.addr.dev = dev->devfn;
     868                 :          0 :         dev->pci.addr.func = 0;
     869                 :          0 :         dev->pci.socket_id = spdk_pci_device_get_socket_id(dev->bus->vmd->pci);
     870                 :          0 :         dev->pci.id.vendor_id = dev->header->common.vendor_id;
     871                 :          0 :         dev->pci.id.device_id = dev->header->common.device_id;
     872                 :          0 :         dev->pci.type = "vmd";
     873                 :          0 :         dev->pci.map_bar = vmd_dev_map_bar;
     874                 :          0 :         dev->pci.unmap_bar = vmd_dev_unmap_bar;
     875                 :          0 :         dev->pci.cfg_read = vmd_dev_cfg_read;
     876                 :          0 :         dev->pci.cfg_write = vmd_dev_cfg_write;
     877                 :          0 :         dev->hotplug_capable = false;
     878         [ #  # ]:          0 :         if (dev->pcie_cap != NULL) {
     879                 :          0 :                 dev->cached_slot_control = dev->pcie_cap->slot_control;
     880                 :            :         }
     881                 :          0 : }
     882                 :            : 
     883                 :            : static int
     884                 :          0 : vmd_init_end_device(struct vmd_pci_device *dev)
     885                 :            : {
     886                 :          0 :         struct vmd_pci_bus *bus = dev->bus;
     887                 :            :         struct vmd_adapter *vmd;
     888                 :            :         struct spdk_pci_driver *driver;
     889                 :          0 :         uint8_t bdf[32];
     890                 :            :         int rc;
     891                 :            : 
     892         [ #  # ]:          0 :         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                 :          0 :         vmd_setup_msix(dev, &bus->vmd->msix_table[0]);
     898                 :          0 :         vmd_dev_init(dev);
     899                 :            : 
     900         [ #  # ]:          0 :         if (vmd_is_supported_device(dev)) {
     901                 :          0 :                 spdk_pci_addr_fmt(bdf, sizeof(bdf), &dev->pci.addr);
     902   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vmd, "Initializing NVMe device at %s\n", bdf);
     903                 :          0 :                 dev->pci.parent = dev->bus->vmd->pci;
     904                 :            : 
     905                 :          0 :                 driver = spdk_pci_nvme_get_driver();
     906         [ #  # ]:          0 :                 assert(driver != NULL);
     907                 :          0 :                 rc = spdk_pci_hook_device(driver, &dev->pci);
     908         [ #  # ]:          0 :                 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                 :          0 :                 vmd = bus->vmd;
     914                 :          0 :                 vmd->target[vmd->nvme_count] = dev;
     915                 :          0 :                 vmd->nvme_count++;
     916                 :            :         }
     917                 :            : 
     918                 :            :         /* Attach the device to the current bus and assign base addresses */
     919                 :          0 :         TAILQ_INSERT_TAIL(&bus->dev_list, dev, tailq);
     920                 :          0 :         g_end_device_count++;
     921                 :            : 
     922                 :          0 :         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                 :          0 : 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                 :          0 :         uint8_t  device_number, dev_cnt = 0;
     953                 :            :         uint8_t new_bus_num;
     954                 :            :         int rc;
     955                 :            : 
     956         [ #  # ]:          0 :         for (device_number = 0; device_number < 32; device_number++) {
     957                 :          0 :                 new_dev = vmd_alloc_dev(bus, device_number);
     958         [ #  # ]:          0 :                 if (new_dev == NULL) {
     959                 :          0 :                         continue;
     960                 :            :                 }
     961                 :            : 
     962         [ #  # ]:          0 :                 if (new_dev->header->common.header_type & PCI_HEADER_TYPE_BRIDGE) {
     963         [ #  # ]:          0 :                         if (hotplug) {
     964                 :          0 :                                 free(new_dev);
     965                 :          0 :                                 continue;
     966                 :            :                         }
     967                 :            : 
     968                 :          0 :                         slot_cap.as_uint32_t = 0;
     969         [ #  # ]:          0 :                         if (new_dev->pcie_cap != NULL) {
     970                 :          0 :                                 slot_cap.as_uint32_t = new_dev->pcie_cap->slot_cap.as_uint32_t;
     971                 :            :                         }
     972                 :            : 
     973                 :          0 :                         new_bus_num = vmd_get_next_bus_number(bus->vmd);
     974         [ #  # ]:          0 :                         if (new_bus_num == 0xff) {
     975                 :          0 :                                 vmd_dev_free(new_dev);
     976                 :          0 :                                 return dev_cnt;
     977                 :            :                         }
     978                 :          0 :                         new_bus = vmd_create_new_bus(bus, new_dev, new_bus_num);
     979         [ #  # ]:          0 :                         if (!new_bus) {
     980                 :          0 :                                 vmd_dev_free(new_dev);
     981                 :          0 :                                 return dev_cnt;
     982                 :            :                         }
     983                 :          0 :                         new_bus->primary_bus = bus->secondary_bus;
     984                 :          0 :                         new_bus->self = new_dev;
     985                 :          0 :                         new_dev->bus_object = new_bus;
     986                 :            : 
     987   [ #  #  #  # ]:          0 :                         if (slot_cap.bit_field.hotplug_capable && new_dev->pcie_cap != NULL &&
     988         [ #  # ]:          0 :                             new_dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
     989                 :          0 :                                 new_bus->hotplug_buses = vmd_get_hotplug_bus_numbers(new_dev);
     990                 :          0 :                                 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   [ #  #  #  # ]:          0 :                                 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                 :          0 :                         new_dev->parent_bridge = parent_bridge;
    1000                 :          0 :                         new_dev->header->one.primary = new_bus->primary_bus;
    1001                 :          0 :                         new_dev->header->one.secondary = new_bus->secondary_bus;
    1002                 :          0 :                         new_dev->header->one.subordinate = new_bus->subordinate_bus;
    1003                 :            : 
    1004                 :          0 :                         vmd_bus_update_bridge_info(new_dev);
    1005                 :          0 :                         TAILQ_INSERT_TAIL(&bus->vmd->bus_list, new_bus, tailq);
    1006                 :            : 
    1007                 :          0 :                         vmd_dev_init(new_dev);
    1008                 :          0 :                         dev_cnt++;
    1009                 :            : 
    1010   [ #  #  #  # ]:          0 :                         if (slot_cap.bit_field.hotplug_capable && new_dev->pcie_cap != NULL &&
    1011         [ #  # ]:          0 :                             new_dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
    1012                 :          0 :                                 vmd_init_hotplug(new_dev, new_bus);
    1013                 :            :                         }
    1014                 :            : 
    1015                 :          0 :                         dev_cnt += vmd_scan_single_bus(new_bus, new_dev, hotplug);
    1016         [ #  # ]:          0 :                         if (new_dev->pcie_cap != NULL) {
    1017         [ #  # ]:          0 :                                 if (new_dev->pcie_cap->express_cap_register.bit_field.device_type == SwitchUpstreamPort) {
    1018                 :          0 :                                         return dev_cnt;
    1019                 :            :                                 }
    1020                 :            :                         }
    1021                 :            :                 } else {
    1022                 :          0 :                         rc = vmd_init_end_device(new_dev);
    1023         [ #  # ]:          0 :                         if (rc != 0) {
    1024                 :          0 :                                 vmd_dev_free(new_dev);
    1025                 :            :                         } else {
    1026                 :          0 :                                 dev_cnt++;
    1027                 :            :                         }
    1028                 :            :                 }
    1029                 :            :         }
    1030                 :            : 
    1031                 :          0 :         return dev_cnt;
    1032                 :            : }
    1033                 :            : 
    1034                 :            : static void
    1035                 :          0 : vmd_print_pci_info(struct vmd_pci_device *dev)
    1036                 :            : {
    1037         [ #  # ]:          0 :         if (!dev) {
    1038                 :          0 :                 return;
    1039                 :            :         }
    1040                 :            : 
    1041         [ #  # ]:          0 :         if (dev->pcie_cap != NULL) {
    1042   [ #  #  #  # ]:          0 :                 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   [ #  #  #  # ]:          0 :         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   [ #  #  #  # ]:          0 :         if (!(dev->header_type & PCI_HEADER_TYPE_BRIDGE) && dev->bus) {
    1055   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vmd, "\tbase addr: %x : %p\n",
    1056                 :            :                              dev->header->zero.BAR[0], (void *)dev->bar[0].vaddr);
    1057                 :            :         }
    1058                 :            : 
    1059         [ #  # ]:          0 :         if ((dev->header_type & PCI_HEADER_TYPE_BRIDGE)) {
    1060   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vmd, "\tPrimary = %d, Secondary = %d, Subordinate = %d\n",
    1061                 :            :                              dev->header->one.primary, dev->header->one.secondary, dev->header->one.subordinate);
    1062   [ #  #  #  # ]:          0 :                 if (dev->pcie_cap && dev->pcie_cap->express_cap_register.bit_field.slot_implemented) {
    1063   [ #  #  #  # ]:          0 :                         SPDK_INFOLOG(vmd, "\tSlot implemented on this device.\n");
    1064         [ #  # ]:          0 :                         if (dev->pcie_cap->slot_cap.bit_field.hotplug_capable) {
    1065   [ #  #  #  # ]:          0 :                                 SPDK_INFOLOG(vmd, "Device has HOT-PLUG capable slot.\n");
    1066                 :            :                         }
    1067                 :            :                 }
    1068                 :            :         }
    1069                 :            : 
    1070         [ #  # ]:          0 :         if (dev->sn_cap != NULL) {
    1071                 :          0 :                 uint8_t *snLow = (uint8_t *)&dev->sn_cap->sn_low;
    1072                 :          0 :                 uint8_t *snHi = (uint8_t *)&dev->sn_cap->sn_hi;
    1073                 :            : 
    1074   [ #  #  #  # ]:          0 :                 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                 :          0 : vmd_cache_scan_info(struct vmd_pci_device *dev)
    1081                 :            : {
    1082                 :            :         uint32_t reg __attribute__((unused));
    1083                 :            : 
    1084         [ #  # ]:          0 :         if (dev->header_type == PCI_HEADER_TYPE_NORMAL) {
    1085                 :          0 :                 return;
    1086                 :            :         }
    1087                 :            : 
    1088   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "vendor/device id:%x:%x\n", dev->header->common.vendor_id,
    1089                 :            :                      dev->header->common.device_id);
    1090                 :            : 
    1091         [ #  # ]:          0 :         if (vmd_device_is_root_port(dev->header)) {
    1092                 :          0 :                 dev->header->one.prefetch_base_upper = VMD_UPPER_BASE_SIGNATURE;
    1093                 :          0 :                 reg = dev->header->one.prefetch_base_upper;
    1094                 :          0 :                 dev->header->one.prefetch_limit_upper = VMD_UPPER_LIMIT_SIGNATURE;
    1095                 :          0 :                 reg = dev->header->one.prefetch_limit_upper;
    1096                 :            : 
    1097   [ #  #  #  # ]:          0 :                 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                 :          0 : 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         [ #  # ]:          0 :         for (devfn = 0; devfn < 32; ++devfn) {
    1118         [ #  # ]:          0 :                 if (!vmd_bus_device_present(bus, devfn)) {
    1119                 :          0 :                         continue;
    1120                 :            :                 }
    1121                 :            : 
    1122                 :          0 :                 header = (volatile void *)(bus->vmd->cfg_vaddr +
    1123         [ #  # ]:          0 :                                            CONFIG_OFFSET_ADDR(bus->config_bus_number, devfn, 0, 0));
    1124   [ #  #  #  # ]:          0 :                 if (vmd_device_is_root_port(header) && !vmd_device_is_enumerated(header)) {
    1125                 :          0 :                         vmd_reset_base_limit_registers(header);
    1126                 :            :                 }
    1127                 :            :         }
    1128                 :          0 : }
    1129                 :            : 
    1130                 :            : static uint8_t
    1131                 :          0 : 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                 :          0 :         vmd_reset_root_ports(bus);
    1138                 :            : 
    1139                 :          0 :         g_end_device_count = 0;
    1140                 :          0 :         TAILQ_INSERT_TAIL(&bus->vmd->bus_list, bus, tailq);
    1141                 :          0 :         bus->vmd->next_bus_number = bus->bus_number + 1;
    1142                 :          0 :         dev_cnt = vmd_scan_single_bus(bus, NULL, false);
    1143                 :            : 
    1144   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "VMD scan found %u devices\n", dev_cnt);
    1145   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "VMD scan found %u END DEVICES\n", g_end_device_count);
    1146                 :            : 
    1147   [ #  #  #  # ]:          0 :         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         [ #  # ]:          0 :         TAILQ_FOREACH(bus_entry, &bus->vmd->bus_list, tailq) {
    1152         [ #  # ]:          0 :                 if (bus_entry->self != NULL) {
    1153                 :          0 :                         vmd_print_pci_info(bus_entry->self);
    1154                 :          0 :                         vmd_cache_scan_info(bus_entry->self);
    1155                 :            :                 }
    1156                 :            : 
    1157         [ #  # ]:          0 :                 TAILQ_FOREACH(dev, &bus_entry->dev_list, tailq) {
    1158                 :          0 :                         vmd_print_pci_info(dev);
    1159                 :            :                 }
    1160                 :            :         }
    1161                 :            : 
    1162                 :          0 :         return dev_cnt;
    1163                 :            : }
    1164                 :            : 
    1165                 :            : static int
    1166                 :          0 : vmd_domain_map_bar(struct vmd_adapter *vmd, uint32_t bar,
    1167                 :            :                    void **vaddr, uint64_t *paddr, uint64_t *size)
    1168                 :            : {
    1169                 :          0 :         uint64_t unused;
    1170                 :            :         int rc;
    1171                 :            : 
    1172                 :          0 :         rc = spdk_pci_device_map_bar(vmd->pci, bar, vaddr, &unused, size);
    1173         [ #  # ]:          0 :         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                 :          0 :         rc = spdk_pci_device_cfg_read(vmd->pci, paddr, sizeof(*paddr),
    1183                 :          0 :                                       PCI_BAR0_OFFSET + bar * PCI_BAR_SIZE);
    1184         [ #  # ]:          0 :         if (rc != 0) {
    1185                 :          0 :                 return rc;
    1186                 :            :         }
    1187                 :            : 
    1188                 :          0 :         *paddr &= PCI_BAR_MEMORY_ADDR_OFFSET;
    1189                 :            : 
    1190                 :          0 :         return 0;
    1191                 :            : }
    1192                 :            : 
    1193                 :            : static int
    1194                 :          0 : vmd_domain_map_bars(struct vmd_adapter *vmd)
    1195                 :            : {
    1196                 :            :         int rc;
    1197                 :            : 
    1198                 :          0 :         rc = vmd_domain_map_bar(vmd, 0, (void **)&vmd->cfg_vaddr,
    1199                 :            :                                 &vmd->cfgbar, &vmd->cfgbar_size);
    1200         [ #  # ]:          0 :         if (rc != 0) {
    1201                 :          0 :                 SPDK_ERRLOG("Failed to map config bar: %s\n", spdk_strerror(-rc));
    1202                 :          0 :                 return rc;
    1203                 :            :         }
    1204                 :            : 
    1205                 :          0 :         rc = vmd_domain_map_bar(vmd, 2, (void **)&vmd->mem_vaddr,
    1206                 :            :                                 &vmd->membar, &vmd->membar_size);
    1207         [ #  # ]:          0 :         if (rc != 0) {
    1208                 :          0 :                 SPDK_ERRLOG("Failed to map memory bar: %s\n", spdk_strerror(-rc));
    1209                 :          0 :                 return rc;
    1210                 :            :         }
    1211                 :            : 
    1212                 :          0 :         vmd->physical_addr = vmd->membar;
    1213                 :          0 :         vmd->current_addr_size = vmd->membar_size;
    1214                 :            : 
    1215                 :          0 :         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                 :          0 : vmd_enumerate_devices(struct vmd_adapter *vmd)
    1241                 :            : {
    1242                 :          0 :         uint8_t max_bus, bus_start;
    1243                 :            : 
    1244                 :          0 :         vmd->vmd_bus.vmd = vmd;
    1245                 :          0 :         vmd->vmd_bus.domain = vmd->pci->addr.domain;
    1246                 :            : 
    1247         [ #  # ]:          0 :         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                 :          0 :                 vmd->vmd_bus.bus_start = 0;
    1255                 :          0 :                 vmd->vmd_bus.secondary_bus = vmd->vmd_bus.subordinate_bus = 0;
    1256                 :          0 :                 vmd->vmd_bus.primary_bus = vmd->vmd_bus.bus_number = 0;
    1257                 :          0 :                 vmd->max_pci_bus = PCI_MAX_BUS_NUMBER;
    1258                 :            :         }
    1259                 :            : 
    1260                 :          0 :         return vmd_scan_pcibus(&vmd->vmd_bus);
    1261                 :            : }
    1262                 :            : 
    1263                 :            : struct vmd_pci_device *
    1264                 :          0 : 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         [ #  # ]:          0 :         for (i = 0; i < g_vmd_container.count; ++i) {
    1271         [ #  # ]:          0 :                 TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
    1272         [ #  # ]:          0 :                         if (bus->self) {
    1273         [ #  # ]:          0 :                                 if (spdk_pci_addr_compare(&bus->self->pci.addr, addr) == 0) {
    1274                 :          0 :                                         return bus->self;
    1275                 :            :                                 }
    1276                 :            :                         }
    1277                 :            : 
    1278         [ #  # ]:          0 :                         TAILQ_FOREACH(dev, &bus->dev_list, tailq) {
    1279         [ #  # ]:          0 :                                 if (spdk_pci_addr_compare(&dev->pci.addr, addr) == 0) {
    1280                 :          0 :                                         return dev;
    1281                 :            :                                 }
    1282                 :            :                         }
    1283                 :            :                 }
    1284                 :            :         }
    1285                 :            : 
    1286                 :          0 :         return NULL;
    1287                 :            : }
    1288                 :            : 
    1289                 :            : static int
    1290                 :          0 : vmd_enum_cb(void *ctx, struct spdk_pci_device *pci_dev)
    1291                 :            : {
    1292                 :          0 :         uint32_t cmd_reg = 0;
    1293                 :          0 :         char bdf[32] = {0};
    1294                 :          0 :         struct vmd_container *vmd_c = ctx;
    1295                 :          0 :         struct vmd_adapter *vmd = &vmd_c->vmd[vmd_c->count];
    1296                 :            : 
    1297                 :          0 :         spdk_pci_device_cfg_read32(pci_dev, &cmd_reg, 4);
    1298                 :          0 :         cmd_reg |= 0x6;                      /* PCI bus master/memory enable. */
    1299                 :          0 :         spdk_pci_device_cfg_write32(pci_dev, cmd_reg, 4);
    1300                 :            : 
    1301                 :          0 :         spdk_pci_addr_fmt(bdf, sizeof(bdf), &pci_dev->addr);
    1302   [ #  #  #  # ]:          0 :         SPDK_INFOLOG(vmd, "Found a VMD[ %d ] at %s\n", vmd_c->count, bdf);
    1303                 :            : 
    1304                 :            :         /* map vmd bars */
    1305                 :          0 :         vmd->pci = pci_dev;
    1306                 :          0 :         vmd->vmd_index = vmd_c->count;
    1307   [ #  #  #  # ]:          0 :         vmd->domain = (pci_dev->addr.bus << 16) | (pci_dev->addr.dev << 8) | pci_dev->addr.func;
    1308                 :          0 :         TAILQ_INIT(&vmd->bus_list);
    1309                 :            : 
    1310         [ #  # ]:          0 :         if (vmd_domain_map_bars(vmd) != 0) {
    1311                 :          0 :                 return -1;
    1312                 :            :         }
    1313                 :            : 
    1314   [ #  #  #  # ]:          0 :         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   [ #  #  #  # ]:          0 :         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                 :          0 :         vmd_c->count++;
    1322                 :          0 :         vmd_enumerate_devices(vmd);
    1323                 :            : 
    1324                 :          0 :         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                 :          0 : vmd_remove_device(struct vmd_pci_device *device)
    1393                 :            : {
    1394                 :          0 :         device->pci.internal.pending_removal = true;
    1395                 :            : 
    1396                 :            :         /* If the device isn't attached, remove it immediately */
    1397   [ #  #  #  # ]:          0 :         if (!device->pci.internal.attached) {
    1398                 :          0 :                 vmd_dev_detach(&device->pci);
    1399                 :            :         }
    1400                 :          0 : }
    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                 :          0 : spdk_vmd_hotplug_monitor(void)
    1416                 :            : {
    1417                 :            :         struct vmd_pci_bus *bus;
    1418                 :            :         struct vmd_pci_device *device;
    1419                 :          0 :         int num_hotplugs = 0;
    1420                 :            :         uint32_t i;
    1421                 :            : 
    1422         [ #  # ]:          0 :         for (i = 0; i < g_vmd_container.count; ++i) {
    1423         [ #  # ]:          0 :                 TAILQ_FOREACH(bus, &g_vmd_container.vmd[i].bus_list, tailq) {
    1424                 :          0 :                         device = bus->self;
    1425   [ #  #  #  #  :          0 :                         if (device == NULL || !device->hotplug_capable) {
                   #  # ]
    1426                 :          0 :                                 continue;
    1427                 :            :                         }
    1428                 :            : 
    1429         [ #  # ]:          0 :                         if (device->pcie_cap->slot_status.bit_field.datalink_state_changed != 1) {
    1430                 :          0 :                                 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                 :          0 :         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                 :        386 : 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         [ -  + ]:        386 :         if (addr->func != 0) {
    1494                 :          0 :                 return -ENODEV;
    1495                 :            :         }
    1496                 :            : 
    1497         [ -  + ]:        386 :         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                 :        386 :         return -ENODEV;
    1530                 :            : }
    1531                 :            : 
    1532                 :            : static void
    1533                 :          0 : vmd_detach_device(struct spdk_pci_device *pci_dev)
    1534                 :            : {
    1535                 :          0 :         struct vmd_pci_device *dev = SPDK_CONTAINEROF(pci_dev, struct vmd_pci_device, pci);
    1536                 :            : 
    1537   [ #  #  #  # ]:          0 :         assert(strcmp(spdk_pci_device_get_type(pci_dev), "vmd") == 0);
    1538         [ #  # ]:          0 :         assert(vmd_find_device(&pci_dev->addr) != NULL);
    1539                 :            : 
    1540                 :          0 :         vmd_remove_device(dev);
    1541                 :          0 : }
    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                 :       2532 : SPDK_PCI_REGISTER_DEVICE_PROVIDER(vmd, &g_vmd_device_provider);
    1550                 :            : 
    1551                 :            : int
    1552                 :          0 : spdk_vmd_init(void)
    1553                 :            : {
    1554                 :          0 :         return spdk_pci_enumerate(spdk_pci_vmd_get_driver(), vmd_enum_cb, &g_vmd_container);
    1555                 :            : }
    1556                 :            : 
    1557                 :            : void
    1558                 :       2022 : spdk_vmd_fini(void)
    1559                 :            : {
    1560                 :            :         uint32_t i;
    1561                 :            : 
    1562         [ -  + ]:       2022 :         for (i = 0; i < g_vmd_container.count; ++i) {
    1563                 :          0 :                 spdk_pci_device_detach(g_vmd_container.vmd[i].pci);
    1564                 :            :         }
    1565                 :       2022 : }
    1566                 :            : 
    1567                 :       2532 : SPDK_LOG_REGISTER_COMPONENT(vmd)

Generated by: LCOV version 1.14