in ifcvf/ifcvf_base.c [99:180]
int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
{
struct virtio_pci_cap cap;
u16 notify_off;
int ret;
u8 pos;
u32 i;
ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos);
if (ret < 0) {
IFCVF_ERR(pdev, "Failed to read PCI capability list\n");
return -EIO;
}
while (pos) {
ret = ifcvf_read_config_range(pdev, (u32 *)&cap,
sizeof(cap), pos);
if (ret < 0) {
IFCVF_ERR(pdev,
"Failed to get PCI capability at %x\n", pos);
break;
}
if (cap.cap_vndr != PCI_CAP_ID_VNDR)
goto next;
switch (cap.cfg_type) {
case VIRTIO_PCI_CAP_COMMON_CFG:
hw->common_cfg = get_cap_addr(hw, &cap);
IFCVF_DBG(pdev, "hw->common_cfg = %p\n",
hw->common_cfg);
break;
case VIRTIO_PCI_CAP_NOTIFY_CFG:
pci_read_config_dword(pdev, pos + sizeof(cap),
&hw->notify_off_multiplier);
hw->notify_bar = cap.bar;
hw->notify_base = get_cap_addr(hw, &cap);
hw->notify_base_pa = pci_resource_start(pdev, cap.bar) +
le32_to_cpu(cap.offset);
IFCVF_DBG(pdev, "hw->notify_base = %p\n",
hw->notify_base);
break;
case VIRTIO_PCI_CAP_ISR_CFG:
hw->isr = get_cap_addr(hw, &cap);
IFCVF_DBG(pdev, "hw->isr = %p\n", hw->isr);
break;
case VIRTIO_PCI_CAP_DEVICE_CFG:
hw->dev_cfg = get_cap_addr(hw, &cap);
IFCVF_DBG(pdev, "hw->dev_cfg = %p\n", hw->dev_cfg);
break;
}
next:
pos = cap.cap_next;
}
if (hw->common_cfg == NULL || hw->notify_base == NULL ||
hw->isr == NULL || hw->dev_cfg == NULL) {
IFCVF_ERR(pdev, "Incomplete PCI capabilities\n");
return -EIO;
}
hw->nr_vring = ifc_ioread16(&hw->common_cfg->num_queues);
for (i = 0; i < hw->nr_vring; i++) {
ifc_iowrite16(i, &hw->common_cfg->queue_select);
notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off);
hw->vring[i].notify_addr = hw->notify_base +
notify_off * hw->notify_off_multiplier;
hw->vring[i].notify_pa = hw->notify_base_pa +
notify_off * hw->notify_off_multiplier;
}
hw->lm_cfg = hw->base[IFCVF_LM_BAR];
IFCVF_DBG(pdev,
"PCI capability mapping: common cfg: %p, notify base: %p\n, isr cfg: %p, device cfg: %p, multiplier: %u\n",
hw->common_cfg, hw->notify_base, hw->isr,
hw->dev_cfg, hw->notify_off_multiplier);
return 0;
}