diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 17:48:30 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 17:48:30 -0500 |
| commit | 515d01f7726b9ba4838787d247115e1b259e1cc7 (patch) | |
| tree | d791be958b963215eefe96b33498269879932191 | |
| parent | 1cef9350cbee6e3bcf2ff646b8978fbec33f8b85 (diff) | |
| parent | d65530fbc799e4036d4d3da4ab6e9fa6d8c4a447 (diff) | |
Merge tag 'vfio-v3.9-rc1' of git://github.com/awilliam/linux-vfio
Pull VFIO updates from Alex Williamson:
- Fixes PCIe v1 extended capability support
- Cleans up read/write access functions
- Fix Removal test to properly wait until devices are unused
- Enable pcieport driver usage for non-accessible devices w/in groups
- Extensions for PCI VGA support
* tag 'vfio-v3.9-rc1' of git://github.com/awilliam/linux-vfio:
drivers/vfio: remove depends on CONFIG_EXPERIMENTAL
vfio-pci: Add support for VGA region access
vfio-pci: Manage user power state transitions
vfio: whitelist pcieport
vfio: Protect vfio_dev_present against device_del
vfio-pci: Cleanup BAR access
vfio-pci: Cleanup read/write functions
vfio-pci: Enable PCIe extended capabilities on v1
| -rw-r--r-- | drivers/vfio/pci/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 75 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 52 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_private.h | 19 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_rdwr.c | 281 | ||||
| -rw-r--r-- | drivers/vfio/vfio.c | 35 | ||||
| -rw-r--r-- | include/uapi/linux/vfio.h | 9 |
7 files changed, 254 insertions, 227 deletions
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 5980758563eb..c41b01e2b693 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig | |||
| @@ -6,3 +6,13 @@ config VFIO_PCI | |||
| 6 | use of PCI drivers using the VFIO framework. | 6 | use of PCI drivers using the VFIO framework. |
| 7 | 7 | ||
| 8 | If you don't know what to do here, say N. | 8 | If you don't know what to do here, say N. |
| 9 | |||
| 10 | config VFIO_PCI_VGA | ||
| 11 | bool "VFIO PCI support for VGA devices" | ||
| 12 | depends on VFIO_PCI && X86 && VGA_ARB | ||
| 13 | help | ||
| 14 | Support for VGA extension to VFIO PCI. This exposes an additional | ||
| 15 | region on VGA devices for accessing legacy VGA addresses used by | ||
| 16 | BIOS and generic video drivers. | ||
| 17 | |||
| 18 | If you don't know what to do here, say N. | ||
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index b28e66c4376a..8189cb6a86af 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
| @@ -84,6 +84,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) | |||
| 84 | } else | 84 | } else |
| 85 | vdev->msix_bar = 0xFF; | 85 | vdev->msix_bar = 0xFF; |
| 86 | 86 | ||
| 87 | #ifdef CONFIG_VFIO_PCI_VGA | ||
| 88 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | ||
| 89 | vdev->has_vga = true; | ||
| 90 | #endif | ||
| 91 | |||
| 87 | return 0; | 92 | return 0; |
| 88 | } | 93 | } |
| 89 | 94 | ||
| @@ -285,6 +290,16 @@ static long vfio_pci_ioctl(void *device_data, | |||
| 285 | info.flags = VFIO_REGION_INFO_FLAG_READ; | 290 | info.flags = VFIO_REGION_INFO_FLAG_READ; |
| 286 | break; | 291 | break; |
| 287 | } | 292 | } |
| 293 | case VFIO_PCI_VGA_REGION_INDEX: | ||
| 294 | if (!vdev->has_vga) | ||
| 295 | return -EINVAL; | ||
| 296 | |||
| 297 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
| 298 | info.size = 0xc0000; | ||
| 299 | info.flags = VFIO_REGION_INFO_FLAG_READ | | ||
| 300 | VFIO_REGION_INFO_FLAG_WRITE; | ||
| 301 | |||
| 302 | break; | ||
| 288 | default: | 303 | default: |
| 289 | return -EINVAL; | 304 | return -EINVAL; |
| 290 | } | 305 | } |
| @@ -366,52 +381,50 @@ static long vfio_pci_ioctl(void *device_data, | |||
| 366 | return -ENOTTY; | 381 | return -ENOTTY; |
| 367 | } | 382 | } |
| 368 | 383 | ||
| 369 | static ssize_t vfio_pci_read(void *device_data, char __user *buf, | 384 | static ssize_t vfio_pci_rw(void *device_data, char __user *buf, |
| 370 | size_t count, loff_t *ppos) | 385 | size_t count, loff_t *ppos, bool iswrite) |
| 371 | { | 386 | { |
| 372 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | 387 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); |
| 373 | struct vfio_pci_device *vdev = device_data; | 388 | struct vfio_pci_device *vdev = device_data; |
| 374 | struct pci_dev *pdev = vdev->pdev; | ||
| 375 | 389 | ||
| 376 | if (index >= VFIO_PCI_NUM_REGIONS) | 390 | if (index >= VFIO_PCI_NUM_REGIONS) |
| 377 | return -EINVAL; | 391 | return -EINVAL; |
| 378 | 392 | ||
| 379 | if (index == VFIO_PCI_CONFIG_REGION_INDEX) | 393 | switch (index) { |
| 380 | return vfio_pci_config_readwrite(vdev, buf, count, ppos, false); | 394 | case VFIO_PCI_CONFIG_REGION_INDEX: |
| 381 | else if (index == VFIO_PCI_ROM_REGION_INDEX) | 395 | return vfio_pci_config_rw(vdev, buf, count, ppos, iswrite); |
| 382 | return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false); | 396 | |
| 383 | else if (pci_resource_flags(pdev, index) & IORESOURCE_IO) | 397 | case VFIO_PCI_ROM_REGION_INDEX: |
| 384 | return vfio_pci_io_readwrite(vdev, buf, count, ppos, false); | 398 | if (iswrite) |
| 385 | else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) | 399 | return -EINVAL; |
| 386 | return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false); | 400 | return vfio_pci_bar_rw(vdev, buf, count, ppos, false); |
| 401 | |||
| 402 | case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: | ||
| 403 | return vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite); | ||
| 404 | |||
| 405 | case VFIO_PCI_VGA_REGION_INDEX: | ||
| 406 | return vfio_pci_vga_rw(vdev, buf, count, ppos, iswrite); | ||
| 407 | } | ||
| 387 | 408 | ||
| 388 | return -EINVAL; | 409 | return -EINVAL; |
| 389 | } | 410 | } |
| 390 | 411 | ||
| 391 | static ssize_t vfio_pci_write(void *device_data, const char __user *buf, | 412 | static ssize_t vfio_pci_read(void *device_data, char __user *buf, |
| 392 | size_t count, loff_t *ppos) | 413 | size_t count, loff_t *ppos) |
| 393 | { | 414 | { |
| 394 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | 415 | if (!count) |
| 395 | struct vfio_pci_device *vdev = device_data; | 416 | return 0; |
| 396 | struct pci_dev *pdev = vdev->pdev; | ||
| 397 | 417 | ||
| 398 | if (index >= VFIO_PCI_NUM_REGIONS) | 418 | return vfio_pci_rw(device_data, buf, count, ppos, false); |
| 399 | return -EINVAL; | 419 | } |
| 400 | 420 | ||
| 401 | if (index == VFIO_PCI_CONFIG_REGION_INDEX) | 421 | static ssize_t vfio_pci_write(void *device_data, const char __user *buf, |
| 402 | return vfio_pci_config_readwrite(vdev, (char __user *)buf, | 422 | size_t count, loff_t *ppos) |
| 403 | count, ppos, true); | 423 | { |
| 404 | else if (index == VFIO_PCI_ROM_REGION_INDEX) | 424 | if (!count) |
| 405 | return -EINVAL; | 425 | return 0; |
| 406 | else if (pci_resource_flags(pdev, index) & IORESOURCE_IO) | ||
| 407 | return vfio_pci_io_readwrite(vdev, (char __user *)buf, | ||
| 408 | count, ppos, true); | ||
| 409 | else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) { | ||
| 410 | return vfio_pci_mem_readwrite(vdev, (char __user *)buf, | ||
| 411 | count, ppos, true); | ||
| 412 | } | ||
| 413 | 426 | ||
| 414 | return -EINVAL; | 427 | return vfio_pci_rw(device_data, (char __user *)buf, count, ppos, true); |
| 415 | } | 428 | } |
| 416 | 429 | ||
| 417 | static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) | 430 | static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) |
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 8b8f7d11e102..964ff22bf281 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c | |||
| @@ -587,12 +587,46 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm) | |||
| 587 | return 0; | 587 | return 0; |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | static int vfio_pm_config_write(struct vfio_pci_device *vdev, int pos, | ||
| 591 | int count, struct perm_bits *perm, | ||
| 592 | int offset, __le32 val) | ||
| 593 | { | ||
| 594 | count = vfio_default_config_write(vdev, pos, count, perm, offset, val); | ||
| 595 | if (count < 0) | ||
| 596 | return count; | ||
| 597 | |||
| 598 | if (offset == PCI_PM_CTRL) { | ||
| 599 | pci_power_t state; | ||
| 600 | |||
| 601 | switch (le32_to_cpu(val) & PCI_PM_CTRL_STATE_MASK) { | ||
| 602 | case 0: | ||
| 603 | state = PCI_D0; | ||
| 604 | break; | ||
| 605 | case 1: | ||
| 606 | state = PCI_D1; | ||
| 607 | break; | ||
| 608 | case 2: | ||
| 609 | state = PCI_D2; | ||
| 610 | break; | ||
| 611 | case 3: | ||
| 612 | state = PCI_D3hot; | ||
| 613 | break; | ||
| 614 | } | ||
| 615 | |||
| 616 | pci_set_power_state(vdev->pdev, state); | ||
| 617 | } | ||
| 618 | |||
| 619 | return count; | ||
| 620 | } | ||
| 621 | |||
| 590 | /* Permissions for the Power Management capability */ | 622 | /* Permissions for the Power Management capability */ |
| 591 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) | 623 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) |
