2014-12-07 19:41:16 +03:00
/*
2014-12-08 13:31:02 +03:00
* Virtio PCI driver - legacy device support
2014-12-07 19:41:16 +03:00
*
* This module allows virtio devices to be used over a virtual PCI device .
* This can be used with QEMU based VMMs like KVM or Xen .
*
* Copyright IBM Corp . 2007
2014-12-08 13:31:02 +03:00
* Copyright Red Hat , Inc . 2014
2014-12-07 19:41:16 +03:00
*
* Authors :
* Anthony Liguori < aliguori @ us . ibm . com >
2014-12-08 13:31:02 +03:00
* Rusty Russell < rusty @ rustcorp . com . au >
* Michael S . Tsirkin < mst @ redhat . com >
2014-12-07 19:41:16 +03:00
*
* This work is licensed under the terms of the GNU GPL , version 2 or later .
* See the COPYING file in the top - level directory .
*
*/
2014-12-08 17:39:45 +03:00
# include "virtio_pci_common.h"
2014-12-07 19:41:16 +03:00
/* virtio config->get_features() implementation */
static u64 vp_get_features ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* When someone needs more than 32 feature bits, we'll need to
* steal a bit to indicate that the rest are somewhere else . */
return ioread32 ( vp_dev - > ioaddr + VIRTIO_PCI_HOST_FEATURES ) ;
}
/* virtio config->finalize_features() implementation */
static int vp_finalize_features ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* Give virtio_ring a chance to accept features. */
vring_transport_features ( vdev ) ;
/* Make sure we don't have any features > 32 bits! */
BUG_ON ( ( u32 ) vdev - > features ! = vdev - > features ) ;
/* We only support 32 feature bits. */
iowrite32 ( vdev - > features , vp_dev - > ioaddr + VIRTIO_PCI_GUEST_FEATURES ) ;
return 0 ;
}
/* virtio config->get() implementation */
static void vp_get ( struct virtio_device * vdev , unsigned offset ,
void * buf , unsigned len )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
void __iomem * ioaddr = vp_dev - > ioaddr +
VIRTIO_PCI_CONFIG ( vp_dev ) + offset ;
u8 * ptr = buf ;
int i ;
for ( i = 0 ; i < len ; i + + )
ptr [ i ] = ioread8 ( ioaddr + i ) ;
}
/* the config->set() implementation. it's symmetric to the config->get()
* implementation */
static void vp_set ( struct virtio_device * vdev , unsigned offset ,
const void * buf , unsigned len )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
void __iomem * ioaddr = vp_dev - > ioaddr +
VIRTIO_PCI_CONFIG ( vp_dev ) + offset ;
const u8 * ptr = buf ;
int i ;
for ( i = 0 ; i < len ; i + + )
iowrite8 ( ptr [ i ] , ioaddr + i ) ;
}
/* config->{get,set}_status() implementations */
static u8 vp_get_status ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
return ioread8 ( vp_dev - > ioaddr + VIRTIO_PCI_STATUS ) ;
}
static void vp_set_status ( struct virtio_device * vdev , u8 status )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* We should never be setting status to 0. */
BUG_ON ( status = = 0 ) ;
iowrite8 ( status , vp_dev - > ioaddr + VIRTIO_PCI_STATUS ) ;
}
static void vp_reset ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* 0 status means a reset. */
iowrite8 ( 0 , vp_dev - > ioaddr + VIRTIO_PCI_STATUS ) ;
/* Flush out the status write, and flush in device writes,
* including MSi - X interrupts , if any . */
ioread8 ( vp_dev - > ioaddr + VIRTIO_PCI_STATUS ) ;
/* Flush pending VQ/configuration callbacks. */
vp_synchronize_vectors ( vdev ) ;
}
static u16 vp_config_vector ( struct virtio_pci_device * vp_dev , u16 vector )
{
/* Setup the vector used for configuration events */
iowrite16 ( vector , vp_dev - > ioaddr + VIRTIO_MSI_CONFIG_VECTOR ) ;
/* Verify we had enough resources to assign the vector */
/* Will also flush the write out to device */
return ioread16 ( vp_dev - > ioaddr + VIRTIO_MSI_CONFIG_VECTOR ) ;
}
static struct virtqueue * setup_vq ( struct virtio_pci_device * vp_dev ,
2017-04-04 21:44:44 +03:00
struct virtio_pci_vq_info * info ,
2014-12-07 19:41:16 +03:00
unsigned index ,
void ( * callback ) ( struct virtqueue * vq ) ,
const char * name ,
u16 msix_vec )
{
struct virtqueue * vq ;
u16 num ;
int err ;
/* Select the queue we're interested in */
iowrite16 ( index , vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_SEL ) ;
/* Check if queue is either not available or already active. */
num = ioread16 ( vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_NUM ) ;
if ( ! num | | ioread32 ( vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_PFN ) )
return ERR_PTR ( - ENOENT ) ;
2017-04-04 21:44:44 +03:00
info - > msix_vector = msix_vec ;
2016-02-03 08:46:39 +03:00
/* create the vring */
vq = vring_create_virtqueue ( index , num ,
VIRTIO_PCI_VRING_ALIGN , & vp_dev - > vdev ,
true , false , vp_notify , callback , name ) ;
if ( ! vq )
2014-12-07 19:41:16 +03:00
return ERR_PTR ( - ENOMEM ) ;
/* activate the queue */
2016-02-03 08:46:39 +03:00
iowrite32 ( virtqueue_get_desc_addr ( vq ) > > VIRTIO_PCI_QUEUE_ADDR_SHIFT ,
2014-12-07 19:41:16 +03:00
vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_PFN ) ;
vq - > priv = ( void __force * ) vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_NOTIFY ;
if ( msix_vec ! = VIRTIO_MSI_NO_VECTOR ) {
iowrite16 ( msix_vec , vp_dev - > ioaddr + VIRTIO_MSI_QUEUE_VECTOR ) ;
msix_vec = ioread16 ( vp_dev - > ioaddr + VIRTIO_MSI_QUEUE_VECTOR ) ;
if ( msix_vec = = VIRTIO_MSI_NO_VECTOR ) {
err = - EBUSY ;
2016-02-03 08:46:39 +03:00
goto out_deactivate ;
2014-12-07 19:41:16 +03:00
}
}
return vq ;
2016-02-03 08:46:39 +03:00
out_deactivate :
2014-12-07 19:41:16 +03:00
iowrite32 ( 0 , vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_PFN ) ;
2016-02-03 08:46:39 +03:00
vring_del_virtqueue ( vq ) ;
2014-12-07 19:41:16 +03:00
return ERR_PTR ( err ) ;
}
2017-04-04 21:44:44 +03:00
static void del_vq ( struct virtio_pci_vq_info * info )
2014-12-07 19:41:16 +03:00
{
2017-04-04 21:44:44 +03:00
struct virtqueue * vq = info - > vq ;
2014-12-07 19:41:16 +03:00
struct virtio_pci_device * vp_dev = to_vp_device ( vq - > vdev ) ;
iowrite16 ( vq - > index , vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_SEL ) ;
2017-04-04 21:09:20 +03:00
if ( vp_dev - > msix_enabled ) {
2014-12-07 19:41:16 +03:00
iowrite16 ( VIRTIO_MSI_NO_VECTOR ,
vp_dev - > ioaddr + VIRTIO_MSI_QUEUE_VECTOR ) ;
/* Flush the write out to device */
ioread8 ( vp_dev - > ioaddr + VIRTIO_PCI_ISR ) ;
}
/* Select and deactivate the queue */
iowrite32 ( 0 , vp_dev - > ioaddr + VIRTIO_PCI_QUEUE_PFN ) ;
2016-02-03 08:46:39 +03:00
vring_del_virtqueue ( vq ) ;
2014-12-07 19:41:16 +03:00
}
static const struct virtio_config_ops virtio_pci_config_ops = {
. get = vp_get ,
. set = vp_set ,
. get_status = vp_get_status ,
. set_status = vp_set_status ,
. reset = vp_reset ,
. find_vqs = vp_find_vqs ,
. del_vqs = vp_del_vqs ,
. get_features = vp_get_features ,
. finalize_features = vp_finalize_features ,
. bus_name = vp_bus_name ,
. set_vq_affinity = vp_set_vq_affinity ,
2017-02-05 20:15:23 +03:00
. get_vq_affinity = vp_get_vq_affinity ,
2014-12-07 19:41:16 +03:00
} ;
/* the PCI probing function */
2015-01-13 12:23:32 +03:00
int virtio_pci_legacy_probe ( struct virtio_pci_device * vp_dev )
2014-12-07 19:41:16 +03:00
{
2015-01-13 12:23:32 +03:00
struct pci_dev * pci_dev = vp_dev - > pci_dev ;
2015-06-24 08:54:15 +03:00
int rc ;
2014-12-07 19:41:16 +03:00
/* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
if ( pci_dev - > device < 0x1000 | | pci_dev - > device > 0x103f )
return - ENODEV ;
if ( pci_dev - > revision ! = VIRTIO_PCI_ABI_VERSION ) {
printk ( KERN_ERR " virtio_pci: expected ABI version %d, got %d \n " ,
VIRTIO_PCI_ABI_VERSION , pci_dev - > revision ) ;
return - ENODEV ;
}
2016-09-14 19:33:26 +03:00
rc = dma_set_mask ( & pci_dev - > dev , DMA_BIT_MASK ( 64 ) ) ;
if ( rc ) {
rc = dma_set_mask_and_coherent ( & pci_dev - > dev , DMA_BIT_MASK ( 32 ) ) ;
} else {
/*
* The virtio ring base address is expressed as a 32 - bit PFN ,
* with a page size of 1 < < VIRTIO_PCI_QUEUE_ADDR_SHIFT .
*/
dma_set_coherent_mask ( & pci_dev - > dev ,
DMA_BIT_MASK ( 32 + VIRTIO_PCI_QUEUE_ADDR_SHIFT ) ) ;
}
2016-02-03 08:46:39 +03:00
if ( rc )
dev_warn ( & pci_dev - > dev , " Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work. \n " ) ;
2015-06-24 08:54:15 +03:00
rc = pci_request_region ( pci_dev , 0 , " virtio-pci-legacy " ) ;
if ( rc )
return rc ;
rc = - ENOMEM ;
2014-12-07 19:41:16 +03:00
vp_dev - > ioaddr = pci_iomap ( pci_dev , 0 , 0 ) ;
2015-01-13 12:23:32 +03:00
if ( ! vp_dev - > ioaddr )
2015-06-24 08:54:15 +03:00
goto err_iomap ;
2014-12-07 19:41:16 +03:00
vp_dev - > isr = vp_dev - > ioaddr + VIRTIO_PCI_ISR ;
/* we use the subsystem vendor/device id as the virtio vendor/device
* id . this allows us to use the same PCI vendor / device id for all
* virtio devices and to identify the particular virtio driver by
* the subsystem ids */
vp_dev - > vdev . id . vendor = pci_dev - > subsystem_vendor ;
vp_dev - > vdev . id . device = pci_dev - > subsystem_device ;
2015-01-13 12:23:32 +03:00
vp_dev - > vdev . config = & virtio_pci_config_ops ;
2014-12-07 19:41:16 +03:00
vp_dev - > config_vector = vp_config_vector ;
vp_dev - > setup_vq = setup_vq ;
vp_dev - > del_vq = del_vq ;
return 0 ;
2015-06-24 08:54:15 +03:00
err_iomap :
pci_release_region ( pci_dev , 0 ) ;
return rc ;
2014-12-07 19:41:16 +03:00
}
2015-01-13 12:23:32 +03:00
void virtio_pci_legacy_remove ( struct virtio_pci_device * vp_dev )
2014-12-07 19:41:16 +03:00
{
2015-01-13 12:23:32 +03:00
struct pci_dev * pci_dev = vp_dev - > pci_dev ;
2014-12-07 19:41:16 +03:00
pci_iounmap ( pci_dev , vp_dev - > ioaddr ) ;
2015-06-24 08:54:15 +03:00
pci_release_region ( pci_dev , 0 ) ;
2014-12-07 19:41:16 +03:00
}