2007-11-12 21:30:26 -06:00
/*
2014-12-08 12:31:02 +02:00
* Virtio PCI driver - common functionality for all device versions
2007-11-12 21:30:26 -06: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 12:31:02 +02:00
* Copyright Red Hat , Inc . 2014
2007-11-12 21:30:26 -06:00
*
* Authors :
* Anthony Liguori < aliguori @ us . ibm . com >
2014-12-08 12:31:02 +02:00
* Rusty Russell < rusty @ rustcorp . com . au >
* Michael S . Tsirkin < mst @ redhat . com >
2007-11-12 21:30:26 -06: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 16:39:45 +02:00
# include "virtio_pci_common.h"
2007-11-12 21:30:26 -06:00
2015-01-15 17:54:13 +02:00
static bool force_legacy = false ;
# if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
module_param ( force_legacy , bool , 0444 ) ;
MODULE_PARM_DESC ( force_legacy ,
" Force legacy mode for transitional virtio 1 devices " ) ;
# endif
2011-11-17 17:41:15 +02:00
/* wait for pending irq handlers */
2014-12-07 18:41:16 +02:00
void vp_synchronize_vectors ( struct virtio_device * vdev )
2011-11-17 17:41:15 +02:00
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
int i ;
2017-02-05 18:15:19 +01:00
synchronize_irq ( pci_irq_vector ( vp_dev - > pci_dev , 0 ) ) ;
for ( i = 1 ; i < vp_dev - > msix_vectors ; i + + )
2016-11-17 11:43:13 +01:00
synchronize_irq ( pci_irq_vector ( vp_dev - > pci_dev , i ) ) ;
2011-11-17 17:41:15 +02:00
}
2007-11-12 21:30:26 -06:00
/* the notify function used when creating a virt queue */
2014-12-07 18:41:16 +02:00
bool vp_notify ( struct virtqueue * vq )
2007-11-12 21:30:26 -06:00
{
/* we write the queue's selector into the notification register to
* signal the other end */
2014-12-03 18:01:58 +02:00
iowrite16 ( vq - > index , ( void __iomem * ) vq - > priv ) ;
2013-10-29 09:38:50 +10:30
return true ;
2007-11-12 21:30:26 -06:00
}
2009-05-14 13:55:31 +03:00
/* Handle a configuration change: Tell driver if it wants to know. */
static irqreturn_t vp_config_changed ( int irq , void * opaque )
{
struct virtio_pci_device * vp_dev = opaque ;
2014-10-14 10:40:34 +10:30
virtio_config_changed ( & vp_dev - > vdev ) ;
2009-05-14 13:55:31 +03:00
return IRQ_HANDLED ;
}
/* Notify all virtqueues on an interrupt. */
static irqreturn_t vp_vring_interrupt ( int irq , void * opaque )
{
struct virtio_pci_device * vp_dev = opaque ;
irqreturn_t ret = IRQ_NONE ;
2017-02-05 18:15:18 +01:00
struct virtqueue * vq ;
2009-05-14 13:55:31 +03:00
2017-02-05 18:15:18 +01:00
list_for_each_entry ( vq , & vp_dev - > vdev . vqs , list ) {
if ( vq - > callback & & vring_interrupt ( irq , vq ) = = IRQ_HANDLED )
2009-05-14 13:55:31 +03:00
ret = IRQ_HANDLED ;
}
return ret ;
}
2007-11-12 21:30:26 -06:00
/* A small wrapper to also acknowledge the interrupt when it's handled.
* I really need an EIO hook for the vring so I can ack the interrupt once we
* know that we ' ll be handling the IRQ but before we invoke the callback since
* the callback may notify the host which results in the host attempting to
* raise an interrupt that we would then mask once we acknowledged the
* interrupt . */
static irqreturn_t vp_interrupt ( int irq , void * opaque )
{
struct virtio_pci_device * vp_dev = opaque ;
u8 isr ;
/* reading the ISR has the effect of also clearing it so it's very
* important to save off the value . */
2014-12-02 14:35:27 +02:00
isr = ioread8 ( vp_dev - > isr ) ;
2007-11-12 21:30:26 -06:00
/* It's definitely not us if the ISR was not high */
if ( ! isr )
return IRQ_NONE ;
/* Configuration change? Tell driver if it wants to know. */
2009-05-14 13:55:31 +03:00
if ( isr & VIRTIO_PCI_ISR_CONFIG )
vp_config_changed ( irq , opaque ) ;
2007-11-12 21:30:26 -06:00
2009-05-14 13:55:31 +03:00
return vp_vring_interrupt ( irq , opaque ) ;
2007-11-12 21:30:26 -06:00
}
2017-02-05 18:15:19 +01:00
static void vp_remove_vqs ( struct virtio_device * vdev )
2009-06-12 22:16:36 -06:00
{
2009-07-26 15:48:08 +03:00
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2009-06-12 22:16:36 -06:00
struct virtqueue * vq , * n ;
2009-07-26 15:48:08 +03:00
list_for_each_entry_safe ( vq , n , & vdev - > vqs , list ) {
2017-02-05 18:15:18 +01:00
if ( vp_dev - > msix_vector_map ) {
int v = vp_dev - > msix_vector_map [ vq - > index ] ;
2016-11-17 11:43:13 +01:00
if ( v ! = VIRTIO_MSI_NO_VECTOR )
free_irq ( pci_irq_vector ( vp_dev - > pci_dev , v ) ,
vq ) ;
}
2017-02-05 18:15:18 +01:00
vp_dev - > del_vq ( vq ) ;
2009-07-26 15:48:08 +03:00
}
2017-02-05 18:15:19 +01:00
}
2009-05-14 13:55:41 +03:00
2017-02-05 18:15:19 +01:00
/* the config->del_vqs() implementation */
void vp_del_vqs ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
int i ;
2016-11-17 11:43:15 +01:00
2017-02-05 18:15:19 +01:00
if ( WARN_ON_ONCE ( list_empty_careful ( & vdev - > vqs ) ) )
return ;
2016-11-17 11:43:15 +01:00
2017-02-05 18:15:19 +01:00
vp_remove_vqs ( vdev ) ;
2016-11-17 11:43:15 +01:00
2017-04-04 21:09:20 +03:00
if ( vp_dev - > msix_enabled ) {
2017-02-05 18:15:19 +01:00
for ( i = 0 ; i < vp_dev - > msix_vectors ; i + + )
free_cpumask_var ( vp_dev - > msix_affinity_masks [ i ] ) ;
2016-11-17 11:43:15 +01:00
/* Disable the vector used for configuration */
vp_dev - > config_vector ( vp_dev , VIRTIO_MSI_NO_VECTOR ) ;
2017-02-05 18:15:19 +01:00
kfree ( vp_dev - > msix_affinity_masks ) ;
kfree ( vp_dev - > msix_names ) ;
kfree ( vp_dev - > msix_vector_map ) ;
2016-11-17 11:43:15 +01:00
}
2017-02-05 18:15:19 +01:00
free_irq ( pci_irq_vector ( vp_dev - > pci_dev , 0 ) , vp_dev ) ;
pci_free_irq_vectors ( vp_dev - > pci_dev ) ;
2009-06-12 22:16:36 -06:00
}
2016-11-17 11:43:16 +01:00
static int vp_find_vqs_msix ( struct virtio_device * vdev , unsigned nvqs ,
2017-02-05 18:15:21 +01:00
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
2017-04-04 21:08:54 +03:00
const char * const names [ ] , bool per_vq_vectors ,
struct irq_affinity * desc )
2009-06-12 22:16:36 -06:00
{
2009-07-26 15:48:08 +03:00
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2017-02-05 18:15:19 +01:00
const char * name = dev_name ( & vp_dev - > vdev . dev ) ;
2017-04-04 21:04:23 +03:00
int i , err = - ENOMEM , allocated_vectors , nvectors ;
2017-02-05 18:15:22 +01:00
unsigned flags = PCI_IRQ_MSIX ;
2009-09-23 22:26:29 -06:00
u16 msix_vec ;
2017-02-05 18:15:19 +01:00
2017-02-05 18:15:22 +01:00
if ( desc ) {
flags | = PCI_IRQ_AFFINITY ;
desc - > pre_vectors + + ; /* virtio config vector */
}
2017-02-05 18:15:19 +01:00
nvectors = 1 ;
for ( i = 0 ; i < nvqs ; i + + )
if ( callbacks [ i ] )
nvectors + + ;
2009-05-14 13:55:41 +03:00
2017-04-04 21:08:54 +03:00
if ( per_vq_vectors ) {
err = pci_alloc_irq_vectors_affinity ( vp_dev - > pci_dev , nvectors ,
nvectors , flags , desc ) ;
} else {
2017-02-05 18:15:19 +01:00
err = pci_alloc_irq_vectors ( vp_dev - > pci_dev , 2 , 2 ,
PCI_IRQ_MSIX ) ;
2009-09-23 22:26:29 -06:00
}
2017-02-05 18:15:19 +01:00
if ( err < 0 )
return err ;
2009-06-12 22:16:36 -06:00
2017-02-05 18:15:19 +01:00
vp_dev - > msix_vectors = nvectors ;
vp_dev - > msix_names = kmalloc_array ( nvectors ,
sizeof ( * vp_dev - > msix_names ) , GFP_KERNEL ) ;
if ( ! vp_dev - > msix_names )
goto out_free_irq_vectors ;
vp_dev - > msix_affinity_masks = kcalloc ( nvectors ,
sizeof ( * vp_dev - > msix_affinity_masks ) , GFP_KERNEL ) ;
if ( ! vp_dev - > msix_affinity_masks )
goto out_free_msix_names ;
for ( i = 0 ; i < nvectors ; + + i ) {
if ( ! alloc_cpumask_var ( & vp_dev - > msix_affinity_masks [ i ] ,
GFP_KERNEL ) )
goto out_free_msix_affinity_masks ;
}
/* Set the vector used for configuration */
snprintf ( vp_dev - > msix_names [ 0 ] , sizeof ( * vp_dev - > msix_names ) ,
" %s-config " , name ) ;
err = request_irq ( pci_irq_vector ( vp_dev - > pci_dev , 0 ) , vp_config_changed ,
0 , vp_dev - > msix_names [ 0 ] , vp_dev ) ;
2016-11-17 11:43:16 +01:00
if ( err )
2017-04-04 21:08:54 +03:00
goto out_free_irq_vectors ;
2016-11-17 11:43:16 +01:00
2017-02-05 18:15:19 +01:00
/* Verify we had enough resources to assign the vector */
if ( vp_dev - > config_vector ( vp_dev , 0 ) = = VIRTIO_MSI_NO_VECTOR ) {
err = - EBUSY ;
goto out_free_config_irq ;
2017-02-05 18:15:18 +01:00
}
2017-02-05 18:15:19 +01:00
vp_dev - > msix_vector_map = kmalloc_array ( nvqs ,
sizeof ( * vp_dev - > msix_vector_map ) , GFP_KERNEL ) ;
if ( ! vp_dev - > msix_vector_map )
goto out_disable_config_irq ;
2017-04-04 21:04:23 +03:00
allocated_vectors = 1 ; /* vector 0 is the config interrupt */
2009-06-12 22:16:36 -06:00
for ( i = 0 ; i < nvqs ; + + i ) {
2012-09-05 21:47:45 +03:00
if ( ! names [ i ] ) {
vqs [ i ] = NULL ;
continue ;
2016-11-17 11:43:16 +01:00
}
2017-02-05 18:15:19 +01:00
if ( callbacks [ i ] )
msix_vec = allocated_vectors ;
2009-07-26 15:48:08 +03:00
else
2017-02-05 18:15:19 +01:00
msix_vec = VIRTIO_MSI_NO_VECTOR ;
2017-02-05 18:15:18 +01:00
vqs [ i ] = vp_dev - > setup_vq ( vp_dev , i , callbacks [ i ] , names [ i ] ,
msix_vec ) ;
2009-07-26 15:48:08 +03:00
if ( IS_ERR ( vqs [ i ] ) ) {
err = PTR_ERR ( vqs [ i ] ) ;
2017-02-05 18:15:19 +01:00
goto out_remove_vqs ;
2009-07-26 15:48:08 +03:00
}
2009-10-22 15:06:06 +02:00
2017-02-05 18:15:18 +01:00
if ( msix_vec = = VIRTIO_MSI_NO_VECTOR ) {
vp_dev - > msix_vector_map [ i ] = VIRTIO_MSI_NO_VECTOR ;
continue ;
}
2017-04-04 21:04:23 +03:00
snprintf ( vp_dev - > msix_names [ i + 1 ] ,
2017-02-05 18:15:19 +01:00
sizeof ( * vp_dev - > msix_names ) , " %s-%s " ,
2009-10-22 15:06:06 +02:00
dev_name ( & vp_dev - > vdev . dev ) , names [ i ] ) ;
2016-11-17 11:43:13 +01:00
err = request_irq ( pci_irq_vector ( vp_dev - > pci_dev , msix_vec ) ,
2017-02-05 18:15:19 +01:00
vring_interrupt , IRQF_SHARED ,
2017-04-04 21:04:23 +03:00
vp_dev - > msix_names [ i + 1 ] , vqs [ i ] ) ;
2017-02-05 18:15:18 +01:00
if ( err ) {
/* don't free this irq on error */
vp_dev - > msix_vector_map [ i ] = VIRTIO_MSI_NO_VECTOR ;
2017-02-05 18:15:19 +01:00
goto out_remove_vqs ;
2017-02-05 18:15:18 +01:00
}
vp_dev - > msix_vector_map [ i ] = msix_vec ;
2017-02-05 18:15:19 +01:00
2017-04-04 21:08:54 +03:00
if ( per_vq_vectors )
2017-02-05 18:15:19 +01:00
allocated_vectors + + ;
2009-06-12 22:16:36 -06:00
}
2017-02-05 18:15:19 +01:00
2017-04-04 21:09:20 +03:00
vp_dev - > msix_enabled = 1 ;
2009-06-12 22:16:36 -06:00
return 0 ;
2017-02-05 18:15:19 +01:00
out_remove_vqs :
vp_remove_vqs ( vdev ) ;
kfree ( vp_dev - > msix_vector_map ) ;
out_disable_config_irq :
vp_dev - > config_vector ( vp_dev , VIRTIO_MSI_NO_VECTOR ) ;
out_free_config_irq :
free_irq ( pci_irq_vector ( vp_dev - > pci_dev , 0 ) , vp_dev ) ;
out_free_msix_affinity_masks :
for ( i = 0 ; i < nvectors ; i + + ) {
if ( vp_dev - > msix_affinity_masks [ i ] )
free_cpumask_var ( vp_dev - > msix_affinity_masks [ i ] ) ;
}
kfree ( vp_dev - > msix_affinity_masks ) ;
out_free_msix_names :
kfree ( vp_dev - > msix_names ) ;
out_free_irq_vectors :
pci_free_irq_vectors ( vp_dev - > pci_dev ) ;
2009-07-26 15:48:08 +03:00
return err ;
}
2016-11-17 11:43:16 +01:00
static int vp_find_vqs_intx ( struct virtio_device * vdev , unsigned nvqs ,
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
const char * const names [ ] )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
int i , err ;
err = request_irq ( vp_dev - > pci_dev - > irq , vp_interrupt , IRQF_SHARED ,
dev_name ( & vdev - > dev ) , vp_dev ) ;
if ( err )
2017-02-05 18:15:19 +01:00
return err ;
2016-11-17 11:43:16 +01:00
for ( i = 0 ; i < nvqs ; + + i ) {
if ( ! names [ i ] ) {
vqs [ i ] = NULL ;
continue ;
}
2017-02-05 18:15:18 +01:00
vqs [ i ] = vp_dev - > setup_vq ( vp_dev , i , callbacks [ i ] , names [ i ] ,
2016-11-17 11:43:16 +01:00
VIRTIO_MSI_NO_VECTOR ) ;
if ( IS_ERR ( vqs [ i ] ) ) {
err = PTR_ERR ( vqs [ i ] ) ;
2017-02-05 18:15:19 +01:00
goto out_remove_vqs ;
2016-11-17 11:43:16 +01:00
}
}
return 0 ;
2017-02-05 18:15:19 +01:00
out_remove_vqs :
vp_remove_vqs ( vdev ) ;
free_irq ( pci_irq_vector ( vp_dev - > pci_dev , 0 ) , vp_dev ) ;
2016-11-17 11:43:16 +01:00
return err ;
}
2009-07-26 15:48:08 +03:00
/* the config->find_vqs() implementation */
2014-12-07 18:41:16 +02:00
int vp_find_vqs ( struct virtio_device * vdev , unsigned nvqs ,
2017-02-05 18:15:22 +01:00
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
const char * const names [ ] , struct irq_affinity * desc )
2009-07-26 15:48:08 +03:00
{
2009-09-23 22:26:29 -06:00
int err ;
2009-07-26 15:48:08 +03:00
2017-04-04 21:08:54 +03:00
/* Try MSI-X with one vector per queue. */
err = vp_find_vqs_msix ( vdev , nvqs , vqs , callbacks , names , true , desc ) ;
if ( ! err )
return 0 ;
/* Fallback: MSI-X with one vector for config, one shared for queues. */
err = vp_find_vqs_msix ( vdev , nvqs , vqs , callbacks , names , false , desc ) ;
2009-07-26 15:48:08 +03:00
if ( ! err )
return 0 ;
2017-04-04 21:08:54 +03:00
/* Finally fall back to regular interrupts. */
2016-11-17 11:43:16 +01:00
return vp_find_vqs_intx ( vdev , nvqs , vqs , callbacks , names ) ;
2009-06-12 22:16:36 -06:00
}
2014-12-07 18:41:16 +02:00
const char * vp_bus_name ( struct virtio_device * vdev )
2011-11-14 14:17:08 +00:00
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
return pci_name ( vp_dev - > pci_dev ) ;
}
2012-08-28 13:54:14 +02:00
/* Setup the affinity for a virtqueue:
* - force the affinity for per vq vector
* - OR over all affinities for shared MSI
* - ignore the affinity request if we ' re using INTX
*/
2014-12-07 18:41:16 +02:00
int vp_set_vq_affinity ( struct virtqueue * vq , int cpu )
2012-08-28 13:54:14 +02:00
{
struct virtio_device * vdev = vq - > vdev ;
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
if ( ! vq - > callback )
return - EINVAL ;
2017-04-04 21:09:20 +03:00
if ( vp_dev - > msix_enabled ) {
2017-02-05 18:15:18 +01:00
int vec = vp_dev - > msix_vector_map [ vq - > index ] ;
struct cpumask * mask = vp_dev - > msix_affinity_masks [ vec ] ;
unsigned int irq = pci_irq_vector ( vp_dev - > pci_dev , vec ) ;
2012-08-28 13:54:14 +02:00
if ( cpu = = - 1 )
irq_set_affinity_hint ( irq , NULL ) ;
else {
2015-06-04 16:41:44 +08:00
cpumask_clear ( mask ) ;
2012-08-28 13:54:14 +02:00
cpumask_set_cpu ( cpu , mask ) ;
irq_set_affinity_hint ( irq , mask ) ;
}
}
return 0 ;
}
2017-02-05 18:15:23 +01:00
const struct cpumask * vp_get_vq_affinity ( struct virtio_device * vdev , int index )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
unsigned int * map = vp_dev - > msix_vector_map ;
if ( ! map | | map [ index ] = = VIRTIO_MSI_NO_VECTOR )
return NULL ;
return pci_irq_get_affinity ( vp_dev - > pci_dev , map [ index ] ) ;
}
2013-09-09 09:57:12 +09:30
# ifdef CONFIG_PM_SLEEP
2011-12-22 16:58:26 +05:30
static int virtio_pci_freeze ( struct device * dev )
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct virtio_pci_device * vp_dev = pci_get_drvdata ( pci_dev ) ;
int ret ;
2014-10-14 10:40:35 +10:30
ret = virtio_device_freeze ( & vp_dev - > vdev ) ;
2011-12-22 16:58:26 +05:30
if ( ! ret )
pci_disable_device ( pci_dev ) ;
return ret ;
}
2012-03-29 12:54:43 +05:30
static int virtio_pci_restore ( struct device * dev )
2011-12-22 16:58:26 +05:30
{
struct pci_dev * pci_dev = to_pci_dev ( dev ) ;
struct virtio_pci_device * vp_dev = pci_get_drvdata ( pci_dev ) ;
int ret ;
ret = pci_enable_device ( pci_dev ) ;
if ( ret )
return ret ;
2012-03-29 12:54:43 +05:30
2011-12-22 16:58:26 +05:30
pci_set_master ( pci_dev ) ;
2014-10-14 10:40:35 +10:30
return virtio_device_restore ( & vp_dev - > vdev ) ;
2011-12-22 16:58:26 +05:30
}
2014-12-11 21:47:49 +02:00
static const struct dev_pm_ops virtio_pci_pm_ops = {
2012-03-29 12:58:05 +05:30
SET_SYSTEM_SLEEP_PM_OPS ( virtio_pci_freeze , virtio_pci_restore )
2011-12-22 16:58:25 +05:30
} ;
2007-11-12 21:30:26 -06:00
# endif
2014-12-11 21:47:49 +02:00
/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
static const struct pci_device_id virtio_pci_id_table [ ] = {
2016-03-06 22:02:30 +00:00
{ PCI_DEVICE ( PCI_VENDOR_ID_REDHAT_QUMRANET , PCI_ANY_ID ) } ,
2014-12-11 21:47:49 +02:00
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , virtio_pci_id_table ) ;
2015-01-13 11:23:32 +02:00
static void virtio_pci_release_dev ( struct device * _d )
{
struct virtio_device * vdev = dev_to_virtio ( _d ) ;
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* As struct device is a kobject, it's not safe to
* free the memory ( including the reference counter itself )
* until it ' s release callback . */
kfree ( vp_dev ) ;
}
2014-12-11 21:47:49 +02:00
static int virtio_pci_probe ( struct pci_dev * pci_dev ,
const struct pci_device_id * id )
{
2015-01-13 11:23:32 +02:00
struct virtio_pci_device * vp_dev ;
int rc ;
/* allocate our structure and fill it out */
vp_dev = kzalloc ( sizeof ( struct virtio_pci_device ) , GFP_KERNEL ) ;
if ( ! vp_dev )
return - ENOMEM ;
pci_set_drvdata ( pci_dev , vp_dev ) ;
vp_dev - > vdev . dev . parent = & pci_dev - > dev ;
vp_dev - > vdev . dev . release = virtio_pci_release_dev ;
vp_dev - > pci_dev = pci_dev ;
/* enable the device */
rc = pci_enable_device ( pci_dev ) ;
if ( rc )
goto err_enable_device ;
2015-01-15 17:54:13 +02:00
if ( force_legacy ) {
2014-12-11 13:59:51 +02:00
rc = virtio_pci_legacy_probe ( vp_dev ) ;
2015-01-15 17:54:13 +02:00
/* Also try modern mode if we can't map BAR0 (no IO space). */
if ( rc = = - ENODEV | | rc = = - ENOMEM )
rc = virtio_pci_modern_probe ( vp_dev ) ;
if ( rc )
goto err_probe ;
} else {
rc = virtio_pci_modern_probe ( vp_dev ) ;
if ( rc = = - ENODEV )
rc = virtio_pci_legacy_probe ( vp_dev ) ;
if ( rc )
goto err_probe ;
}
2015-01-13 11:23:32 +02:00
pci_set_master ( pci_dev ) ;
rc = register_virtio_device ( & vp_dev - > vdev ) ;
if ( rc )
goto err_register ;
return 0 ;
err_register :
2014-12-11 13:59:51 +02:00
if ( vp_dev - > ioaddr )
virtio_pci_legacy_remove ( vp_dev ) ;
else
virtio_pci_modern_remove ( vp_dev ) ;
2015-01-13 11:23:32 +02:00
err_probe :
pci_disable_device ( pci_dev ) ;
err_enable_device :
kfree ( vp_dev ) ;
return rc ;
2014-12-11 21:47:49 +02:00
}
static void virtio_pci_remove ( struct pci_dev * pci_dev )
{
2015-01-13 11:23:32 +02:00
struct virtio_pci_device * vp_dev = pci_get_drvdata ( pci_dev ) ;
2016-01-14 16:00:41 +02:00
struct device * dev = get_device ( & vp_dev - > vdev . dev ) ;
2015-01-13 11:23:32 +02:00
unregister_virtio_device ( & vp_dev - > vdev ) ;
2014-12-11 13:59:51 +02:00
if ( vp_dev - > ioaddr )
virtio_pci_legacy_remove ( vp_dev ) ;
else
virtio_pci_modern_remove ( vp_dev ) ;
2015-01-13 11:23:32 +02:00
pci_disable_device ( pci_dev ) ;
2016-01-14 16:00:41 +02:00
put_device ( dev ) ;
2014-12-11 21:47:49 +02:00
}
static struct pci_driver virtio_pci_driver = {
. name = " virtio-pci " ,
. id_table = virtio_pci_id_table ,
. probe = virtio_pci_probe ,
. remove = virtio_pci_remove ,
# ifdef CONFIG_PM_SLEEP
. driver . pm = & virtio_pci_pm_ops ,
# endif
} ;
module_pci_driver ( virtio_pci_driver ) ;
2014-12-17 00:54:03 +02:00
MODULE_AUTHOR ( " Anthony Liguori <aliguori@us.ibm.com> " ) ;
MODULE_DESCRIPTION ( " virtio-pci " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( " 1 " ) ;