Skip to content

Commit

Permalink
Merge tag 'vfio-v3.9-rc1' of git://github.com/awilliam/linux-vfio
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torvalds committed Feb 26, 2013
2 parents 1cef935 + d65530f commit 515d01f
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 227 deletions.
10 changes: 10 additions & 0 deletions drivers/vfio/pci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,13 @@ config VFIO_PCI
use of PCI drivers using the VFIO framework.

If you don't know what to do here, say N.

config VFIO_PCI_VGA
bool "VFIO PCI support for VGA devices"
depends on VFIO_PCI && X86 && VGA_ARB
help
Support for VGA extension to VFIO PCI. This exposes an additional
region on VGA devices for accessing legacy VGA addresses used by
BIOS and generic video drivers.

If you don't know what to do here, say N.
75 changes: 44 additions & 31 deletions drivers/vfio/pci/vfio_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
} else
vdev->msix_bar = 0xFF;

#ifdef CONFIG_VFIO_PCI_VGA
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
vdev->has_vga = true;
#endif

return 0;
}

Expand Down Expand Up @@ -285,6 +290,16 @@ static long vfio_pci_ioctl(void *device_data,
info.flags = VFIO_REGION_INFO_FLAG_READ;
break;
}
case VFIO_PCI_VGA_REGION_INDEX:
if (!vdev->has_vga)
return -EINVAL;

info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
info.size = 0xc0000;
info.flags = VFIO_REGION_INFO_FLAG_READ |
VFIO_REGION_INFO_FLAG_WRITE;

break;
default:
return -EINVAL;
}
Expand Down Expand Up @@ -366,52 +381,50 @@ static long vfio_pci_ioctl(void *device_data,
return -ENOTTY;
}

static ssize_t vfio_pci_read(void *device_data, char __user *buf,
size_t count, loff_t *ppos)
static ssize_t vfio_pci_rw(void *device_data, char __user *buf,
size_t count, loff_t *ppos, bool iswrite)
{
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
struct vfio_pci_device *vdev = device_data;
struct pci_dev *pdev = vdev->pdev;

if (index >= VFIO_PCI_NUM_REGIONS)
return -EINVAL;

if (index == VFIO_PCI_CONFIG_REGION_INDEX)
return vfio_pci_config_readwrite(vdev, buf, count, ppos, false);
else if (index == VFIO_PCI_ROM_REGION_INDEX)
return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
return vfio_pci_io_readwrite(vdev, buf, count, ppos, false);
else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM)
return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
switch (index) {
case VFIO_PCI_CONFIG_REGION_INDEX:
return vfio_pci_config_rw(vdev, buf, count, ppos, iswrite);

case VFIO_PCI_ROM_REGION_INDEX:
if (iswrite)
return -EINVAL;
return vfio_pci_bar_rw(vdev, buf, count, ppos, false);

case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
return vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite);

case VFIO_PCI_VGA_REGION_INDEX:
return vfio_pci_vga_rw(vdev, buf, count, ppos, iswrite);
}

return -EINVAL;
}

static ssize_t vfio_pci_write(void *device_data, const char __user *buf,
size_t count, loff_t *ppos)
static ssize_t vfio_pci_read(void *device_data, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
struct vfio_pci_device *vdev = device_data;
struct pci_dev *pdev = vdev->pdev;
if (!count)
return 0;

if (index >= VFIO_PCI_NUM_REGIONS)
return -EINVAL;
return vfio_pci_rw(device_data, buf, count, ppos, false);
}

if (index == VFIO_PCI_CONFIG_REGION_INDEX)
return vfio_pci_config_readwrite(vdev, (char __user *)buf,
count, ppos, true);
else if (index == VFIO_PCI_ROM_REGION_INDEX)
return -EINVAL;
else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
return vfio_pci_io_readwrite(vdev, (char __user *)buf,
count, ppos, true);
else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) {
return vfio_pci_mem_readwrite(vdev, (char __user *)buf,
count, ppos, true);
}
static ssize_t vfio_pci_write(void *device_data, const char __user *buf,
size_t count, loff_t *ppos)
{
if (!count)
return 0;

return -EINVAL;
return vfio_pci_rw(device_data, (char __user *)buf, count, ppos, true);
}

static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
Expand Down
52 changes: 43 additions & 9 deletions drivers/vfio/pci/vfio_pci_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -587,23 +587,58 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm)
return 0;
}

static int vfio_pm_config_write(struct vfio_pci_device *vdev, int pos,
int count, struct perm_bits *perm,
int offset, __le32 val)
{
count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
if (count < 0)
return count;

if (offset == PCI_PM_CTRL) {
pci_power_t state;

switch (le32_to_cpu(val) & PCI_PM_CTRL_STATE_MASK) {
case 0:
state = PCI_D0;
break;
case 1:
state = PCI_D1;
break;
case 2:
state = PCI_D2;
break;
case 3:
state = PCI_D3hot;
break;
}

pci_set_power_state(vdev->pdev, state);
}

return count;
}

/* Permissions for the Power Management capability */
static int __init init_pci_cap_pm_perm(struct perm_bits *perm)
{
if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM]))
return -ENOMEM;

perm->writefn = vfio_pm_config_write;

/*
* We always virtualize the next field so we can remove
* capabilities from the chain if we want to.
*/
p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);

/*
* Power management is defined *per function*,
* so we let the user write this
* Power management is defined *per function*, so we can let
* the user change power state, but we trap and initiate the
* change ourselves, so the state bits are read-only.
*/
p_setd(perm, PCI_PM_CTRL, NO_VIRT, ALL_WRITE);
p_setd(perm, PCI_PM_CTRL, NO_VIRT, ~PCI_PM_CTRL_STATE_MASK);
return 0;
}

Expand Down Expand Up @@ -985,12 +1020,12 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
if (ret)
return pcibios_err_to_errno(ret);

vdev->extended_caps = true;

if ((word & PCI_EXP_FLAGS_VERS) == 1)
return PCI_CAP_EXP_ENDPOINT_SIZEOF_V1;
else {
vdev->extended_caps = true;
else
return PCI_CAP_EXP_ENDPOINT_SIZEOF_V2;
}
case PCI_CAP_ID_HT:
ret = pci_read_config_byte(pdev, pos + 3, &byte);
if (ret)
Expand Down Expand Up @@ -1501,9 +1536,8 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
return ret;
}

ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev,
char __user *buf, size_t count,
loff_t *ppos, bool iswrite)
ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite)
{
size_t done = 0;
int ret = 0;
Expand Down
19 changes: 10 additions & 9 deletions drivers/vfio/pci/vfio_pci_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct vfio_pci_device {
bool reset_works;
bool extended_caps;
bool bardirty;
bool has_vga;
struct pci_saved_state *pci_saved_state;
atomic_t refcnt;
};
Expand All @@ -70,15 +71,15 @@ extern int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev,
uint32_t flags, unsigned index,
unsigned start, unsigned count, void *data);

extern ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev,
char __user *buf, size_t count,
loff_t *ppos, bool iswrite);
extern ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev,
char __user *buf, size_t count,
loff_t *ppos, bool iswrite);
extern ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev,
char __user *buf, size_t count,
loff_t *ppos, bool iswrite);
extern ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev,
char __user *buf, size_t count,
loff_t *ppos, bool iswrite);

extern ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite);

extern ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite);

extern int vfio_pci_init_perm_bits(void);
extern void vfio_pci_uninit_perm_bits(void);
Expand Down
Loading

0 comments on commit 515d01f

Please sign in to comment.