aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/vfio/pci/vfio_pci.c286
-rw-r--r--include/uapi/linux/vfio.h38
2 files changed, 323 insertions, 1 deletions
</
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index cef6002acbd4..6ab71b9fcf8d 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/eventfd.h> 15#include <linux/eventfd.h>
16#include <linux/file.h>
16#include <linux/interrupt.h> 17#include <linux/interrupt.h>
17#include <linux/iommu.h> 18#include <linux/iommu.h>
18#include <linux/module.h> 19#include <linux/module.h>
@@ -227,6 +228,110 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
227 return 0; 228 return 0;
228} 229}
229 230
231static int vfio_pci_count_devs(struct pci_dev *pdev, void *data)
232{
233 (*(int *)data)++;
234 return 0;
235}
236
237struct vfio_pci_fill_info {
238 int max;
239 int cur;
240 struct vfio_pci_dependent_device *devices;
241};
242
243static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)
244{
245 struct vfio_pci_fill_info *fill = data;
246 struct iommu_group *iommu_group;
247
248 if (fill->cur == fill->max)
249 return -EAGAIN; /* Something changed, try again */
250
251 iommu_group = iommu_group_get(&pdev->dev);
252 if (!iommu_group)
253 return -EPERM; /* Cannot reset non-isolated devices */
254
255 fill->devices[fill->cur].group_id = iommu_group_id(iommu_group);
256 fill->devices[fill->cur].segment = pci_domain_nr(pdev->bus);
257 fill->devices[fill->cur].bus = pdev->bus->number;
258 fill->devices[fill->cur].devfn = pdev->devfn;
259 fill->cur++;
260 iommu_group_put(iommu_group);
261 return 0;
262}
263
264struct vfio_pci_group_entry {
265 struct vfio_group *group;
266 int id;
267};
268
269struct vfio_pci_group_info {
270 int count;
271 struct vfio_pci_group_entry *groups;
272};
273
274static int vfio_pci_validate_devs(struct pci_dev *pdev, void *data)
275{
276 struct vfio_pci_group_info *info = data;
277 struct iommu_group *group;
278 int id, i;
279
280 group = iommu_group_get(&pdev->dev);
281 if (!group)
282 return -EPERM;
283
284 id = iommu_group_id(group);
285
286 for (i = 0; i < info->count; i++)
287 if (info->groups[i].id == id)
288 break;
289
290 iommu_group_put(group);
291
292 return (i == info->count) ? -EINVAL : 0;
293}
294
295static bool vfio_pci_dev_below_slot(struct pci_dev *pdev, struct pci_slot *slot)
296{
297 for (; pdev; pdev = pdev->bus->self)
298 if (pdev->bus == slot->bus)
299 return (pdev->slot == slot);
300 return false;
301}
302
303struct vfio_pci_walk_info {
304 int (*fn)(struct pci_dev *, void *data);
305 void *data;
306 struct pci_dev *pdev;
307 bool slot;
308 int ret;
309};
310
311static int vfio_pci_walk_wrapper(struct pci_dev *pdev, void *data)
312{
313 struct vfio_pci_walk_info *walk = data;
314
315 if (!walk->slot || vfio_pci_dev_below_slot(pdev, walk->pdev->slot))
316 walk->ret = walk->fn(pdev, walk->data);
317
318 return walk->ret;
319}
320
321static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
322 int (*fn)(struct pci_dev *,
323 void *data), void *data,
324 bool slot)
325{
326 struct vfio_pci_walk_info walk = {
327 .fn = fn, .data = data, .pdev = pdev, .slot = slot, .ret = 0,
328 };
329
330 pci_walk_bus(pdev->bus, vfio_pci_walk_wrapper, &walk);
331
332 return walk.ret;
333}
334
230static long vfio_pci_ioctl(void *device_data, 335static long vfio_pci_ioctl(void *device_data,
231 unsigned int cmd, unsigned long arg) 336 unsigned int cmd, unsigned long arg)
232{ 337{
@@ -407,10 +512,189 @@ static long vfio_pci_ioctl(void *device_data,
407 512
408 return ret; 513 return ret;
409 514
410 } else if (cmd == VFIO_DEVICE_RESET) 515 } else if (cmd == VFIO_DEVICE_RESET) {
411 return vdev->reset_works ? 516 return vdev->reset_works ?
412 pci_reset_function(vdev->pdev) : -EINVAL; 517 pci_reset_function(vdev->pdev) : -EINVAL;
413 518
519 } else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {
520 struct vfio_pci_hot_reset_info hdr;
521 struct vfio_pci_fill_info fill = { 0 };
522 struct vfio_pci_dependent_device *devices = NULL;
523 bool slot = false;
524 int ret = 0;
525
526 minsz = offsetofend(struct vfio_pci_hot_reset_info, count);
527
528 if (copy_from_user(&hdr, (void __user *)arg, minsz))
529 return -EFAULT;
530
531 if (hdr.argsz < minsz)
532 return -EINVAL;
533
534 hdr.flags = 0;
535
536 /* Can we do a slot or bus reset or neither? */
537 if (!pci_probe_reset_slot(vdev->pdev->slot))
538 slot = true;
539 else if (pci_probe_reset_bus(vdev->pdev->bus))
540 return -ENODEV;
541
542 /* How many devices are affected? */
543 ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
544 vfio_pci_count_devs,
545 &fill.max, slot);
546 if (ret)
547 return ret;
548
549 WARN_ON(!fill.max); /* Should always be at least one */
550
551 /*
552 * If there's enough space, fill it now, otherwise return
553 * -ENOSPC and the number of devices affected.
554 */
555 if (hdr.argsz < sizeof(hdr) + (fill.max * sizeof(*devices))) {
556 ret = -ENOSPC;
557 hdr.count = fill.max;
558 goto reset_info_exit;
559 }
560
561 devices = kcalloc(fill.max, sizeof(*devices), GFP_KERNEL);
562 if (!devices)
563 return -ENOMEM;
564
565 fill.devices = devices;
566
567 ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
568 vfio_pci_fill_devs,
569 &fill, slot);
570
571 /*
572 * If a device was removed between counting and filling,
573 * we may come up short of fill.max. If a device was
574 * added, we'll have a return of -EAGAIN above.
575 */
576 if (!ret)
577 hdr.count = fill.cur;
578
579reset_info_exit:
580 if (copy_to_user((void __user *)arg, &hdr, minsz))
581 ret = -EFAULT;
582
583 if (!ret) {
584 if (copy_to_user((void __user *)(arg + minsz), devices,
585 hdr.count * sizeof(*devices)))
586 ret = -EFAULT;
587 }
588
589 kfree(devices);
590 return ret;
591
592 } else if (cmd == VFIO_DEVICE_PCI_HOT_RESET) {
593 struct vfio_pci_hot_reset hdr;
594 int32_t *group_fds;
595 struct vfio_pci_group_entry *groups;
596 struct vfio_pci_group_info info;
597 bool slot = false;
598 int i, count = 0, ret = 0;