Commit b3c0a866 authored by Kirti Wankhede's avatar Kirti Wankhede Committed by Alex Williamson
Browse files

vfio: Introduce common function to add capabilities



Vendor driver using mediated device framework should use
vfio_info_add_capability() to add capabilities.
Introduced this function to reduce code duplication in vendor drivers.

vfio_info_cap_shift() manipulated a data buffer to add an offset to each
element in a chain. This data buffer is documented in a uapi header.
Changing vfio_info_cap_shift symbol to be available to all drivers.

Signed-off-by: default avatarKirti Wankhede <kwankhede@nvidia.com>
Signed-off-by: default avatarNeo Jia <cjia@nvidia.com>
Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent c086de81
Loading
Loading
Loading
Loading
+59 −1
Original line number Diff line number Diff line
@@ -1797,8 +1797,66 @@ void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
	for (tmp = caps->buf; tmp->next; tmp = (void *)tmp + tmp->next - offset)
		tmp->next += offset;
}
EXPORT_SYMBOL_GPL(vfio_info_cap_shift);
EXPORT_SYMBOL(vfio_info_cap_shift);

static int sparse_mmap_cap(struct vfio_info_cap *caps, void *cap_type)
{
	struct vfio_info_cap_header *header;
	struct vfio_region_info_cap_sparse_mmap *sparse_cap, *sparse = cap_type;
	size_t size;

	size = sizeof(*sparse) + sparse->nr_areas *  sizeof(*sparse->areas);
	header = vfio_info_cap_add(caps, size,
				   VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
	if (IS_ERR(header))
		return PTR_ERR(header);

	sparse_cap = container_of(header,
			struct vfio_region_info_cap_sparse_mmap, header);
	sparse_cap->nr_areas = sparse->nr_areas;
	memcpy(sparse_cap->areas, sparse->areas,
	       sparse->nr_areas * sizeof(*sparse->areas));
	return 0;
}

static int region_type_cap(struct vfio_info_cap *caps, void *cap_type)
{
	struct vfio_info_cap_header *header;
	struct vfio_region_info_cap_type *type_cap, *cap = cap_type;

	header = vfio_info_cap_add(caps, sizeof(*cap),
				   VFIO_REGION_INFO_CAP_TYPE, 1);
	if (IS_ERR(header))
		return PTR_ERR(header);

	type_cap = container_of(header, struct vfio_region_info_cap_type,
				header);
	type_cap->type = cap->type;
	type_cap->subtype = cap->subtype;
	return 0;
}

int vfio_info_add_capability(struct vfio_info_cap *caps, int cap_type_id,
			     void *cap_type)
{
	int ret = -EINVAL;

	if (!cap_type)
		return 0;

	switch (cap_type_id) {
	case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
		ret = sparse_mmap_cap(caps, cap_type);
		break;

	case VFIO_REGION_INFO_CAP_TYPE:
		ret = region_type_cap(caps, cap_type);
		break;
	}

	return ret;
}
EXPORT_SYMBOL(vfio_info_add_capability);

/*
 * Pin a set of guest PFNs and return their associated host PFNs for local
+3 −0
Original line number Diff line number Diff line
@@ -126,6 +126,9 @@ extern struct vfio_info_cap_header *vfio_info_cap_add(
		struct vfio_info_cap *caps, size_t size, u16 id, u16 version);
extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);

extern int vfio_info_add_capability(struct vfio_info_cap *caps,
				    int cap_type_id, void *cap_type);

struct pci_dev;
#ifdef CONFIG_EEH
extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);