Commit 30e920e1 authored by Ankit Agrawal's avatar Ankit Agrawal Committed by Alex Williamson

vfio/pci: rename and export range_intersect_range

range_intersect_range determines an overlap between two ranges. If an
overlap, the helper function returns the overlapping offset and size.

The VFIO PCI variant driver emulates the PCI config space BAR offset
registers. These offset may be accessed for read/write with a variety
of lengths including sub-word sizes from sub-word offsets. The driver
makes use of this helper function to read/write the targeted part of
the emulated register.

Make this a vfio_pci_core function, rename and export as GPL. Also
update references in virtio driver.
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarYishai Hadas <yishaih@nvidia.com>
Signed-off-by: default avatarAnkit Agrawal <ankita@nvidia.com>
Link: https://lore.kernel.org/r/20240220115055.23546-3-ankita@nvidia.comSigned-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 4de676d4
...@@ -1966,3 +1966,45 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, ...@@ -1966,3 +1966,45 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf,
return done; return done;
} }
/**
* vfio_pci_core_range_intersect_range() - Determine overlap between a buffer
* and register offset ranges.
* @buf_start: start offset of the buffer
* @buf_cnt: number of buffer bytes
* @reg_start: start register offset
* @reg_cnt: number of register bytes
* @buf_offset: start offset of overlap in the buffer
* @intersect_count: number of overlapping bytes
* @register_offset: start offset of overlap in register
*
* Returns: true if there is overlap, false if not.
* The overlap start and size is returned through function args.
*/
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
loff_t reg_start, size_t reg_cnt,
loff_t *buf_offset,
size_t *intersect_count,
size_t *register_offset)
{
if (buf_start <= reg_start &&
buf_start + buf_cnt > reg_start) {
*buf_offset = reg_start - buf_start;
*intersect_count = min_t(size_t, reg_cnt,
buf_start + buf_cnt - reg_start);
*register_offset = 0;
return true;
}
if (buf_start > reg_start &&
buf_start < reg_start + reg_cnt) {
*buf_offset = 0;
*intersect_count = min_t(size_t, buf_cnt,
reg_start + reg_cnt - buf_start);
*register_offset = buf_start - reg_start;
return true;
}
return false;
}
EXPORT_SYMBOL_GPL(vfio_pci_core_range_intersect_range);
...@@ -132,33 +132,6 @@ virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev, ...@@ -132,33 +132,6 @@ virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev,
return ret ? ret : count; return ret ? ret : count;
} }
static bool range_intersect_range(loff_t range1_start, size_t count1,
loff_t range2_start, size_t count2,
loff_t *start_offset,
size_t *intersect_count,
size_t *register_offset)
{
if (range1_start <= range2_start &&
range1_start + count1 > range2_start) {
*start_offset = range2_start - range1_start;
*intersect_count = min_t(size_t, count2,
range1_start + count1 - range2_start);
*register_offset = 0;
return true;
}
if (range1_start > range2_start &&
range1_start < range2_start + count2) {
*start_offset = 0;
*intersect_count = min_t(size_t, count1,
range2_start + count2 - range1_start);
*register_offset = range1_start - range2_start;
return true;
}
return false;
}
static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
char __user *buf, size_t count, char __user *buf, size_t count,
loff_t *ppos) loff_t *ppos)
...@@ -178,16 +151,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, ...@@ -178,16 +151,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (range_intersect_range(pos, count, PCI_DEVICE_ID, sizeof(val16), if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID,
&copy_offset, &copy_count, &register_offset)) { sizeof(val16), &copy_offset,
&copy_count, &register_offset)) {
val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET); val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET);
if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count)) if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count))
return -EFAULT; return -EFAULT;
} }
if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) && if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) &&
range_intersect_range(pos, count, PCI_COMMAND, sizeof(val16), vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND,
&copy_offset, &copy_count, &register_offset)) { sizeof(val16), &copy_offset,
&copy_count, &register_offset)) {
if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset, if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset,
copy_count)) copy_count))
return -EFAULT; return -EFAULT;
...@@ -197,16 +172,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, ...@@ -197,16 +172,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
return -EFAULT; return -EFAULT;
} }
if (range_intersect_range(pos, count, PCI_REVISION_ID, sizeof(val8), if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID,
&copy_offset, &copy_count, &register_offset)) { sizeof(val8), &copy_offset,
&copy_count, &register_offset)) {
/* Transional needs to have revision 0 */ /* Transional needs to have revision 0 */
val8 = 0; val8 = 0;
if (copy_to_user(buf + copy_offset, &val8, copy_count)) if (copy_to_user(buf + copy_offset, &val8, copy_count))
return -EFAULT; return -EFAULT;
} }
if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, sizeof(val32), if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
&copy_offset, &copy_count, &register_offset)) { sizeof(val32), &copy_offset,
&copy_count, &register_offset)) {
u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1); u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1);
u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0); u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0);
...@@ -215,8 +192,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, ...@@ -215,8 +192,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
return -EFAULT; return -EFAULT;
} }
if (range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, sizeof(val16), if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_ID,
&copy_offset, &copy_count, &register_offset)) { sizeof(val16), &copy_offset,
&copy_count, &register_offset)) {
/* /*
* Transitional devices use the PCI subsystem device id as * Transitional devices use the PCI subsystem device id as
* virtio device id, same as legacy driver always did. * virtio device id, same as legacy driver always did.
...@@ -227,8 +205,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, ...@@ -227,8 +205,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
return -EFAULT; return -EFAULT;
} }
if (range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, sizeof(val16), if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID,
&copy_offset, &copy_count, &register_offset)) { sizeof(val16), &copy_offset,
&copy_count, &register_offset)) {
val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET); val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET);
if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
copy_count)) copy_count))
...@@ -270,19 +249,20 @@ static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev, ...@@ -270,19 +249,20 @@ static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev,
loff_t copy_offset; loff_t copy_offset;
size_t copy_count; size_t copy_count;
if (range_intersect_range(pos, count, PCI_COMMAND, sizeof(virtvdev->pci_cmd), if (vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND,
&copy_offset, &copy_count, sizeof(virtvdev->pci_cmd),
&register_offset)) { &copy_offset, &copy_count,
&register_offset)) {
if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset, if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset,
buf + copy_offset, buf + copy_offset,
copy_count)) copy_count))
return -EFAULT; return -EFAULT;
} }
if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
sizeof(virtvdev->pci_base_addr_0), sizeof(virtvdev->pci_base_addr_0),
&copy_offset, &copy_count, &copy_offset, &copy_count,
&register_offset)) { &register_offset)) {
if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset, if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset,
buf + copy_offset, buf + copy_offset,
copy_count)) copy_count))
......
...@@ -134,6 +134,11 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, ...@@ -134,6 +134,11 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
void __iomem *io, char __user *buf, void __iomem *io, char __user *buf,
loff_t off, size_t count, size_t x_start, loff_t off, size_t count, size_t x_start,
size_t x_end, bool iswrite); size_t x_end, bool iswrite);
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
loff_t reg_start, size_t reg_cnt,
loff_t *buf_offset,
size_t *intersect_count,
size_t *register_offset);
#define VFIO_IOWRITE_DECLATION(size) \ #define VFIO_IOWRITE_DECLATION(size) \
int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \ int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \
bool test_mem, u##size val, void __iomem *io); bool test_mem, u##size val, void __iomem *io);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment