+ ret = rte_pci_read_config(pci_dev, &pos, 1, PCI_CAPABILITY_LIST);
+ if (ret != 1) {
+ PMD_INIT_LOG(DEBUG,
+ "failed to read pci capability list, ret %d", ret);
+ return -1;
+ }
+
+ while (pos) {
+ ret = rte_pci_read_config(pci_dev, &cap, 2, pos);
+ if (ret != 2) {
+ PMD_INIT_LOG(DEBUG,
+ "failed to read pci cap at pos: %x ret %d",
+ pos, ret);
+ break;
+ }
+
+ if (cap.cap_vndr == PCI_CAP_ID_MSIX) {
+ /* Transitional devices would also have this capability,
+ * that's why we also check if msix is enabled.
+ * 1st byte is cap ID; 2nd byte is the position of next
+ * cap; next two bytes are the flags.
+ */
+ uint16_t flags;
+
+ ret = rte_pci_read_config(pci_dev, &flags, sizeof(flags),
+ pos + 2);
+ if (ret != sizeof(flags)) {
+ PMD_INIT_LOG(DEBUG,
+ "failed to read pci cap at pos:"
+ " %x ret %d", pos + 2, ret);
+ break;
+ }
+
+ if (flags & PCI_MSIX_ENABLE)
+ dev->msix_status = VIRTIO_MSIX_ENABLED;
+ else
+ dev->msix_status = VIRTIO_MSIX_DISABLED;
+ }
+
+ if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+ PMD_INIT_LOG(DEBUG,
+ "[%2x] skipping non VNDR cap id: %02x",
+ pos, cap.cap_vndr);
+ goto next;
+ }
+
+ ret = rte_pci_read_config(pci_dev, &cap, sizeof(cap), pos);
+ if (ret != sizeof(cap)) {
+ PMD_INIT_LOG(DEBUG,
+ "failed to read pci cap at pos: %x ret %d",
+ pos, ret);
+ break;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+ pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+ switch (cap.cfg_type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ dev->common_cfg = get_cfg_addr(pci_dev, &cap);
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ ret = rte_pci_read_config(pci_dev,
+ &dev->notify_off_multiplier,
+ 4, pos + sizeof(cap));
+ if (ret != 4)
+ PMD_INIT_LOG(DEBUG,
+ "failed to read notify_off_multiplier, ret %d",
+ ret);
+ else
+ dev->notify_base = get_cfg_addr(pci_dev, &cap);
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ dev->dev_cfg = get_cfg_addr(pci_dev, &cap);
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ dev->isr = get_cfg_addr(pci_dev, &cap);
+ break;
+ }
+
+next:
+ pos = cap.cap_next;
+ }
+
+ if (dev->common_cfg == NULL || dev->notify_base == NULL ||
+ dev->dev_cfg == NULL || dev->isr == NULL) {
+ PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+ return -1;
+ }
+
+ PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+ PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", dev->common_cfg);
+ PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", dev->dev_cfg);
+ PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", dev->isr);
+ PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+ dev->notify_base, dev->notify_off_multiplier);
+
+ return 0;