int ifcvf_init_hw()

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;
}