@ -800,9 +800,6 @@ static int vfio_find_cap_start(struct vfio_pci_device *vdev, int pos)
u8 cap ;
int base = ( pos > = PCI_CFG_SPACE_SIZE ) ? PCI_CFG_SPACE_SIZE :
PCI_STD_HEADER_SIZEOF ;
base / = 4 ;
pos / = 4 ;
cap = vdev - > pci_config_map [ pos ] ;
if ( cap = = PCI_CAP_ID_BASIC )
@ -812,7 +809,7 @@ static int vfio_find_cap_start(struct vfio_pci_device *vdev, int pos)
while ( pos - 1 > = base & & vdev - > pci_config_map [ pos - 1 ] = = cap )
pos - - ;
return pos * 4 ;
return pos ;
}
static int vfio_msi_config_read ( struct vfio_pci_device * vdev , int pos ,
@ -1229,8 +1226,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
}
/* Sanity check, do we overlap other capabilities? */
for ( i = 0 ; i < len ; i + = 4 ) {
if ( likely ( map [ ( pos + i ) / 4 ] = = PCI_CAP_ID_INVALID ) )
for ( i = 0 ; i < len ; i + + ) {
if ( likely ( map [ pos + i ] = = PCI_CAP_ID_INVALID ) )
continue ;
pr_warn ( " %s: %s pci config conflict @0x%x, was cap 0x%x now cap 0x%x \n " ,
@ -1238,7 +1235,7 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
pos + i , map [ pos + i ] , cap ) ;
}
memset ( map + ( pos / 4 ) , cap , len / 4 ) ;
memset ( map + pos , cap , len ) ;
ret = vfio_fill_vconfig_bytes ( vdev , pos , len ) ;
if ( ret )
return ret ;
@ -1313,8 +1310,8 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
hidden = true ;
}
for ( i = 0 ; i < len ; i + = 4 ) {
if ( likely ( map [ ( epos + i ) / 4 ] = = PCI_CAP_ID_INVALID ) )
for ( i = 0 ; i < len ; i + + ) {
if ( likely ( map [ epos + i ] = = PCI_CAP_ID_INVALID ) )
continue ;
pr_warn ( " %s: %s pci config conflict @0x%x, was ecap 0x%x now ecap 0x%x \n " ,
@ -1329,7 +1326,7 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
*/
BUILD_BUG_ON ( PCI_EXT_CAP_ID_MAX > = PCI_CAP_ID_INVALID ) ;
memset ( map + ( epos / 4 ) , ecap , len / 4 ) ;
memset ( map + epos , ecap , len ) ;
ret = vfio_fill_vconfig_bytes ( vdev , epos , len ) ;
if ( ret )
return ret ;
@ -1376,10 +1373,12 @@ int vfio_config_init(struct vfio_pci_device *vdev)
int ret ;
/*
* Config space , caps and ecaps are all dword aligned , so we can
* use one byte per dword to record the type .
* Config space , caps and ecaps are all dword aligned , so we could
* use one byte per dword to record the type . However , there are
* no requiremenst on the length of a capability , so the gap between
* capabilities needs byte granularity .
*/
map = kmalloc ( pdev - > cfg_size / 4 , GFP_KERNEL ) ;
map = kmalloc ( pdev - > cfg_size , GFP_KERNEL ) ;
if ( ! map )
return - ENOMEM ;
@ -1392,9 +1391,9 @@ int vfio_config_init(struct vfio_pci_device *vdev)
vdev - > pci_config_map = map ;
vdev - > vconfig = vconfig ;
memset ( map , PCI_CAP_ID_BASIC , PCI_STD_HEADER_SIZEOF / 4 ) ;
memset ( map + ( PCI_STD_HEADER_SIZEOF / 4 ) , PCI_CAP_ID_INVALID ,
( pdev - > cfg_size - PCI_STD_HEADER_SIZEOF ) / 4 ) ;
memset ( map , PCI_CAP_ID_BASIC , PCI_STD_HEADER_SIZEOF ) ;
memset ( map + PCI_STD_HEADER_SIZEOF , PCI_CAP_ID_INVALID ,
pdev - > cfg_size - PCI_STD_HEADER_SIZEOF ) ;
ret = vfio_fill_vconfig_bytes ( vdev , 0 , PCI_STD_HEADER_SIZEOF ) ;
if ( ret )
@ -1449,6 +1448,22 @@ void vfio_config_free(struct vfio_pci_device *vdev)
vdev - > msi_perm = NULL ;
}
/*
* Find the remaining number of bytes in a dword that match the given
* position . Stop at either the end of the capability or the dword boundary .
*/
static size_t vfio_pci_cap_remaining_dword ( struct vfio_pci_device * vdev ,
loff_t pos )
{
u8 cap = vdev - > pci_config_map [ pos ] ;
size_t i ;
for ( i = 1 ; ( pos + i ) % 4 & & vdev - > pci_config_map [ pos + i ] = = cap ; i + + )
/* nop */ ;
return i ;
}
static ssize_t vfio_config_do_rw ( struct vfio_pci_device * vdev , char __user * buf ,
size_t count , loff_t * ppos , bool iswrite )
{
@ -1457,19 +1472,27 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
__le32 val = 0 ;
int cap_start = 0 , offset ;
u8 cap_id ;
ssize_t ret = count ;
ssize_t ret ;
if ( * ppos < 0 | | * ppos + count > pdev - > cfg_size )
if ( * ppos < 0 | | * ppos > = pdev - > cfg_size | |
* ppos + count > pdev - > cfg_size )
return - EFAULT ;
/*
* gcc can ' t seem to figure out we ' re a static function , only called
* with count of 1 / 2 / 4 and hits copy_from_user_overflow without this .
* Chop accesses into aligned chunks containing no more than a
* single capability . Caller increments to the next chunk .
*/
if ( count > sizeof ( val ) )
return - EINVAL ;
count = min ( count , vfio_pci_cap_remaining_dword ( vdev , * ppos ) ) ;
if ( count > = 4 & & ! ( * ppos % 4 ) )
count = 4 ;
else if ( count > = 2 & & ! ( * ppos % 2 ) )
count = 2 ;
else
count = 1 ;
ret = count ;
cap_id = vdev - > pci_config_map [ * ppos / 4 ] ;
cap_id = vdev - > pci_config_map [ * ppos ] ;
if ( cap_id = = PCI_CAP_ID_INVALID ) {
if ( iswrite )
@ -1485,11 +1508,6 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf,
return ret ;
}
/*
* All capabilities are minimum 4 bytes and aligned on dword
* boundaries . Since we don ' t support unaligned accesses , we ' re
* only ever accessing a single capability .
*/
if ( * ppos > = PCI_CFG_SPACE_SIZE ) {
WARN_ON ( cap_id > PCI_EXT_CAP_ID_MAX ) ;
@ -1545,20 +1563,8 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev, char __user *buf,
pos & = VFIO_PCI_OFFSET_MASK ;
/*
* We want to both keep the access size the caller users as well as
* support reading large chunks of config space in a single call .
* PCI doesn ' t support unaligned accesses , so we can safely break
* those apart .
*/
while ( count ) {
if ( count > = 4 & & ! ( pos % 4 ) )
ret = vfio_config_do_rw ( vdev , buf , 4 , & pos , iswrite ) ;
else if ( count > = 2 & & ! ( pos % 2 ) )
ret = vfio_config_do_rw ( vdev , buf , 2 , & pos , iswrite ) ;
else
ret = vfio_config_do_rw ( vdev , buf , 1 , & pos , iswrite ) ;
ret = vfio_config_do_rw ( vdev , buf , count , & pos , iswrite ) ;
if ( ret < 0 )
return ret ;