Skip to content

Commit 30e920e

Browse files
ankita-nvawilliam
authored andcommitted
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: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Yishai Hadas <yishaih@nvidia.com> Signed-off-by: Ankit Agrawal <ankita@nvidia.com> Link: https://lore.kernel.org/r/20240220115055.23546-3-ankita@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent 4de676d commit 30e920e

File tree

3 files changed

+73
-46
lines changed

3 files changed

+73
-46
lines changed

drivers/vfio/pci/vfio_pci_config.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,3 +1966,45 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf,
19661966

19671967
return done;
19681968
}
1969+
1970+
/**
1971+
* vfio_pci_core_range_intersect_range() - Determine overlap between a buffer
1972+
* and register offset ranges.
1973+
* @buf_start: start offset of the buffer
1974+
* @buf_cnt: number of buffer bytes
1975+
* @reg_start: start register offset
1976+
* @reg_cnt: number of register bytes
1977+
* @buf_offset: start offset of overlap in the buffer
1978+
* @intersect_count: number of overlapping bytes
1979+
* @register_offset: start offset of overlap in register
1980+
*
1981+
* Returns: true if there is overlap, false if not.
1982+
* The overlap start and size is returned through function args.
1983+
*/
1984+
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
1985+
loff_t reg_start, size_t reg_cnt,
1986+
loff_t *buf_offset,
1987+
size_t *intersect_count,
1988+
size_t *register_offset)
1989+
{
1990+
if (buf_start <= reg_start &&
1991+
buf_start + buf_cnt > reg_start) {
1992+
*buf_offset = reg_start - buf_start;
1993+
*intersect_count = min_t(size_t, reg_cnt,
1994+
buf_start + buf_cnt - reg_start);
1995+
*register_offset = 0;
1996+
return true;
1997+
}
1998+
1999+
if (buf_start > reg_start &&
2000+
buf_start < reg_start + reg_cnt) {
2001+
*buf_offset = 0;
2002+
*intersect_count = min_t(size_t, buf_cnt,
2003+
reg_start + reg_cnt - buf_start);
2004+
*register_offset = buf_start - reg_start;
2005+
return true;
2006+
}
2007+
2008+
return false;
2009+
}
2010+
EXPORT_SYMBOL_GPL(vfio_pci_core_range_intersect_range);

drivers/vfio/pci/virtio/main.c

Lines changed: 26 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -132,33 +132,6 @@ virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev,
132132
return ret ? ret : count;
133133
}
134134

135-
static bool range_intersect_range(loff_t range1_start, size_t count1,
136-
loff_t range2_start, size_t count2,
137-
loff_t *start_offset,
138-
size_t *intersect_count,
139-
size_t *register_offset)
140-
{
141-
if (range1_start <= range2_start &&
142-
range1_start + count1 > range2_start) {
143-
*start_offset = range2_start - range1_start;
144-
*intersect_count = min_t(size_t, count2,
145-
range1_start + count1 - range2_start);
146-
*register_offset = 0;
147-
return true;
148-
}
149-
150-
if (range1_start > range2_start &&
151-
range1_start < range2_start + count2) {
152-
*start_offset = 0;
153-
*intersect_count = min_t(size_t, count1,
154-
range2_start + count2 - range1_start);
155-
*register_offset = range1_start - range2_start;
156-
return true;
157-
}
158-
159-
return false;
160-
}
161-
162135
static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
163136
char __user *buf, size_t count,
164137
loff_t *ppos)
@@ -178,16 +151,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
178151
if (ret < 0)
179152
return ret;
180153

181-
if (range_intersect_range(pos, count, PCI_DEVICE_ID, sizeof(val16),
182-
&copy_offset, &copy_count, &register_offset)) {
154+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID,
155+
sizeof(val16), &copy_offset,
156+
&copy_count, &register_offset)) {
183157
val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET);
184158
if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count))
185159
return -EFAULT;
186160
}
187161

188162
if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) &&
189-
range_intersect_range(pos, count, PCI_COMMAND, sizeof(val16),
190-
&copy_offset, &copy_count, &register_offset)) {
163+
vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND,
164+
sizeof(val16), &copy_offset,
165+
&copy_count, &register_offset)) {
191166
if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset,
192167
copy_count))
193168
return -EFAULT;
@@ -197,16 +172,18 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
197172
return -EFAULT;
198173
}
199174

200-
if (range_intersect_range(pos, count, PCI_REVISION_ID, sizeof(val8),
201-
&copy_offset, &copy_count, &register_offset)) {
175+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID,
176+
sizeof(val8), &copy_offset,
177+
&copy_count, &register_offset)) {
202178
/* Transional needs to have revision 0 */
203179
val8 = 0;
204180
if (copy_to_user(buf + copy_offset, &val8, copy_count))
205181
return -EFAULT;
206182
}
207183

208-
if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, sizeof(val32),
209-
&copy_offset, &copy_count, &register_offset)) {
184+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
185+
sizeof(val32), &copy_offset,
186+
&copy_count, &register_offset)) {
210187
u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1);
211188
u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0);
212189

@@ -215,8 +192,9 @@ static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
215192
return -EFAULT;
216193
}
217194

218-
if (range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, sizeof(val16),
219-
&copy_offset, &copy_count, &register_offset)) {
195+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_ID,
196+
sizeof(val16), &copy_offset,
197+
&copy_count, &register_offset)) {
220198
/*
221199
* Transitional devices use the PCI subsystem device id as
222200
* 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,
227205
return -EFAULT;
228206
}
229207

230-
if (range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, sizeof(val16),
231-
&copy_offset, &copy_count, &register_offset)) {
208+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID,
209+
sizeof(val16), &copy_offset,
210+
&copy_count, &register_offset)) {
232211
val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET);
233212
if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
234213
copy_count))
@@ -270,19 +249,20 @@ static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev,
270249
loff_t copy_offset;
271250
size_t copy_count;
272251

273-
if (range_intersect_range(pos, count, PCI_COMMAND, sizeof(virtvdev->pci_cmd),
274-
&copy_offset, &copy_count,
275-
&register_offset)) {
252+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND,
253+
sizeof(virtvdev->pci_cmd),
254+
&copy_offset, &copy_count,
255+
&register_offset)) {
276256
if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset,
277257
buf + copy_offset,
278258
copy_count))
279259
return -EFAULT;
280260
}
281261

282-
if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
283-
sizeof(virtvdev->pci_base_addr_0),
284-
&copy_offset, &copy_count,
285-
&register_offset)) {
262+
if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
263+
sizeof(virtvdev->pci_base_addr_0),
264+
&copy_offset, &copy_count,
265+
&register_offset)) {
286266
if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset,
287267
buf + copy_offset,
288268
copy_count))

include/linux/vfio_pci_core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
134134
void __iomem *io, char __user *buf,
135135
loff_t off, size_t count, size_t x_start,
136136
size_t x_end, bool iswrite);
137+
bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
138+
loff_t reg_start, size_t reg_cnt,
139+
loff_t *buf_offset,
140+
size_t *intersect_count,
141+
size_t *register_offset);
137142
#define VFIO_IOWRITE_DECLATION(size) \
138143
int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \
139144
bool test_mem, u##size val, void __iomem *io);

0 commit comments

Comments
 (0)