in virtio_pci_modern.c [289:346]
static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id,
u8 *bar, u64 *offset, u64 *len)
{
int pos;
for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); pos > 0;
pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
u8 type, cap_len, id;
u32 tmp32;
u64 res_offset, res_length;
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
cfg_type), &type);
if (type != VIRTIO_PCI_CAP_SHARED_MEMORY_CFG)
continue;
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
cap_len), &cap_len);
if (cap_len != sizeof(struct virtio_pci_cap64)) {
dev_err(&dev->dev, "%s: shm cap with bad size offset:"
" %d size: %d\n", __func__, pos, cap_len);
continue;
}
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
id), &id);
if (id != required_id)
continue;
/* Type, and ID match, looks good */
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
bar), bar);
/* Read the lower 32bit of length and offset */
pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap,
offset), &tmp32);
res_offset = tmp32;
pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap,
length), &tmp32);
res_length = tmp32;
/* and now the top half */
pci_read_config_dword(dev,
pos + offsetof(struct virtio_pci_cap64,
offset_hi), &tmp32);
res_offset |= ((u64)tmp32) << 32;
pci_read_config_dword(dev,
pos + offsetof(struct virtio_pci_cap64,
length_hi), &tmp32);
res_length |= ((u64)tmp32) << 32;
*offset = res_offset;
*len = res_length;
return pos;
}
return 0;
}