2007-11-13 06:30:26 +03:00
/*
2014-12-08 13:31:02 +03:00
* Virtio PCI driver - common functionality for all device versions
2007-11-13 06:30:26 +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
2007-11-13 06:30:26 +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 >
2007-11-13 06:30:26 +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"
2007-11-13 06:30:26 +03:00
2015-01-15 18:54:13 +03: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 19:41:15 +04:00
/* wait for pending irq handlers */
2014-12-07 19:41:16 +03:00
void vp_synchronize_vectors ( struct virtio_device * vdev )
2011-11-17 19:41:15 +04:00
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
int i ;
2017-04-04 21:15:41 +03:00
if ( vp_dev - > intx_enabled )
synchronize_irq ( vp_dev - > pci_dev - > irq ) ;
for ( i = 0 ; i < vp_dev - > msix_vectors ; + + i )
2016-11-17 13:43:13 +03:00
synchronize_irq ( pci_irq_vector ( vp_dev - > pci_dev , i ) ) ;
2011-11-17 19:41:15 +04:00
}
2007-11-13 06:30:26 +03:00
/* the notify function used when creating a virt queue */
2014-12-07 19:41:16 +03:00
bool vp_notify ( struct virtqueue * vq )
2007-11-13 06:30:26 +03:00
{
/* we write the queue's selector into the notification register to
* signal the other end */
2014-12-03 19:01:58 +03:00
iowrite16 ( vq - > index , ( void __iomem * ) vq - > priv ) ;
2013-10-29 03:08:50 +04:00
return true ;
2007-11-13 06:30:26 +03:00
}
2009-05-14 14:55:31 +04: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 04:10:34 +04:00
virtio_config_changed ( & vp_dev - > vdev ) ;
2009-05-14 14:55:31 +04: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 ;
2017-04-04 21:44:44 +03:00
struct virtio_pci_vq_info * info ;
2009-05-14 14:55:31 +04:00
irqreturn_t ret = IRQ_NONE ;
2017-04-04 21:44:44 +03:00
unsigned long flags ;
2009-05-14 14:55:31 +04:00
2017-04-04 21:44:44 +03:00
spin_lock_irqsave ( & vp_dev - > lock , flags ) ;
list_for_each_entry ( info , & vp_dev - > virtqueues , node ) {
if ( vring_interrupt ( irq , info - > vq ) = = IRQ_HANDLED )
2009-05-14 14:55:31 +04:00
ret = IRQ_HANDLED ;
}
2017-04-04 21:44:44 +03:00
spin_unlock_irqrestore ( & vp_dev - > lock , flags ) ;
2009-05-14 14:55:31 +04:00
return ret ;
}
2007-11-13 06:30:26 +03: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 15:35:27 +03:00
isr = ioread8 ( vp_dev - > isr ) ;
2007-11-13 06:30:26 +03: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 14:55:31 +04:00
if ( isr & VIRTIO_PCI_ISR_CONFIG )
vp_config_changed ( irq , opaque ) ;
2007-11-13 06:30:26 +03:00
2009-05-14 14:55:31 +04:00
return vp_vring_interrupt ( irq , opaque ) ;
2007-11-13 06:30:26 +03:00
}
2017-04-04 21:15:41 +03:00
static int vp_request_msix_vectors ( struct virtio_device * vdev , int nvectors ,
bool per_vq_vectors , struct irq_affinity * desc )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
const char * name = dev_name ( & vp_dev - > vdev . dev ) ;
2017-08-24 19:07:02 +03:00
unsigned flags = PCI_IRQ_MSIX ;
2017-04-04 21:15:41 +03:00
unsigned i , v ;
int err = - ENOMEM ;
vp_dev - > msix_vectors = nvectors ;
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
vp_dev - > msix_names = kmalloc_array ( nvectors ,
sizeof ( * vp_dev - > msix_names ) ,
GFP_KERNEL ) ;
2017-04-04 21:15:41 +03:00
if ( ! vp_dev - > msix_names )
goto error ;
vp_dev - > msix_affinity_masks
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
= kcalloc ( nvectors , sizeof ( * vp_dev - > msix_affinity_masks ) ,
2017-04-04 21:15:41 +03:00
GFP_KERNEL ) ;
if ( ! vp_dev - > msix_affinity_masks )
goto error ;
for ( i = 0 ; i < nvectors ; + + i )
if ( ! alloc_cpumask_var ( & vp_dev - > msix_affinity_masks [ i ] ,
GFP_KERNEL ) )
goto error ;
2017-08-24 19:07:02 +03:00
if ( desc ) {
flags | = PCI_IRQ_AFFINITY ;
desc - > pre_vectors + + ; /* virtio config vector */
}
2017-04-04 21:15:41 +03:00
err = pci_alloc_irq_vectors_affinity ( vp_dev - > pci_dev , nvectors ,
2017-08-24 19:07:02 +03:00
nvectors , flags , desc ) ;
2017-04-04 21:15:41 +03:00
if ( err < 0 )
goto error ;
vp_dev - > msix_enabled = 1 ;
/* Set the vector used for configuration */
v = vp_dev - > msix_used_vectors ;
snprintf ( vp_dev - > msix_names [ v ] , sizeof * vp_dev - > msix_names ,
" %s-config " , name ) ;
err = request_irq ( pci_irq_vector ( vp_dev - > pci_dev , v ) ,
vp_config_changed , 0 , vp_dev - > msix_names [ v ] ,
vp_dev ) ;
if ( err )
goto error ;
+ + vp_dev - > msix_used_vectors ;
v = vp_dev - > config_vector ( vp_dev , v ) ;
/* Verify we had enough resources to assign the vector */
if ( v = = VIRTIO_MSI_NO_VECTOR ) {
err = - EBUSY ;
goto error ;
}
if ( ! per_vq_vectors ) {
/* Shared vector for all VQs */
v = vp_dev - > msix_used_vectors ;
snprintf ( vp_dev - > msix_names [ v ] , sizeof * vp_dev - > msix_names ,
" %s-virtqueues " , name ) ;
err = request_irq ( pci_irq_vector ( vp_dev - > pci_dev , v ) ,
vp_vring_interrupt , 0 , vp_dev - > msix_names [ v ] ,
vp_dev ) ;
if ( err )
goto error ;
+ + vp_dev - > msix_used_vectors ;
}
return 0 ;
error :
return err ;
}
2017-04-04 21:44:44 +03:00
static struct virtqueue * vp_setup_vq ( struct virtio_device * vdev , unsigned index ,
void ( * callback ) ( struct virtqueue * vq ) ,
const char * name ,
2017-03-06 19:32:29 +03:00
bool ctx ,
2017-04-04 21:44:44 +03:00
u16 msix_vec )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
struct virtio_pci_vq_info * info = kmalloc ( sizeof * info , GFP_KERNEL ) ;
struct virtqueue * vq ;
unsigned long flags ;
/* fill out our structure that represents an active queue */
if ( ! info )
return ERR_PTR ( - ENOMEM ) ;
2017-03-06 19:32:29 +03:00
vq = vp_dev - > setup_vq ( vp_dev , info , index , callback , name , ctx ,
2017-04-04 21:44:44 +03:00
msix_vec ) ;
if ( IS_ERR ( vq ) )
goto out_info ;
info - > vq = vq ;
if ( callback ) {
spin_lock_irqsave ( & vp_dev - > lock , flags ) ;
list_add ( & info - > node , & vp_dev - > virtqueues ) ;
spin_unlock_irqrestore ( & vp_dev - > lock , flags ) ;
} else {
INIT_LIST_HEAD ( & info - > node ) ;
}
vp_dev - > vqs [ index ] = info ;
return vq ;
out_info :
kfree ( info ) ;
return vq ;
}
static void vp_del_vq ( struct virtqueue * vq )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vq - > vdev ) ;
struct virtio_pci_vq_info * info = vp_dev - > vqs [ vq - > index ] ;
unsigned long flags ;
spin_lock_irqsave ( & vp_dev - > lock , flags ) ;
list_del ( & info - > node ) ;
spin_unlock_irqrestore ( & vp_dev - > lock , flags ) ;
vp_dev - > del_vq ( info ) ;
kfree ( info ) ;
}
2017-04-04 21:15:41 +03:00
/* the config->del_vqs() implementation */
void vp_del_vqs ( struct virtio_device * vdev )
2009-06-13 08:16:36 +04:00
{
2009-07-26 16:48:08 +04:00
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2009-06-13 08:16:36 +04:00
struct virtqueue * vq , * n ;
2017-04-04 21:15:41 +03:00
int i ;
2009-06-13 08:16:36 +04:00
2009-07-26 16:48:08 +04:00
list_for_each_entry_safe ( vq , n , & vdev - > vqs , list ) {
2017-04-04 21:44:44 +03:00
if ( vp_dev - > per_vq_vectors ) {
int v = vp_dev - > vqs [ vq - > index ] - > msix_vector ;
2016-11-17 13:43:13 +03:00
2017-03-08 11:09:27 +03:00
if ( v ! = VIRTIO_MSI_NO_VECTOR ) {
int irq = pci_irq_vector ( vp_dev - > pci_dev , v ) ;
irq_set_affinity_hint ( irq , NULL ) ;
free_irq ( irq , vq ) ;
}
2016-11-17 13:43:13 +03:00
}
2017-04-04 21:44:44 +03:00
vp_del_vq ( vq ) ;
2009-07-26 16:48:08 +04:00
}
2017-04-04 21:44:44 +03:00
vp_dev - > per_vq_vectors = false ;
2009-05-14 14:55:41 +04:00
2017-04-04 21:15:41 +03:00
if ( vp_dev - > intx_enabled ) {
free_irq ( vp_dev - > pci_dev - > irq , vp_dev ) ;
vp_dev - > intx_enabled = 0 ;
}
2016-11-17 13:43:15 +03:00
2017-04-04 21:15:41 +03:00
for ( i = 0 ; i < vp_dev - > msix_used_vectors ; + + i )
free_irq ( pci_irq_vector ( vp_dev - > pci_dev , i ) , vp_dev ) ;
2016-11-17 13:43:15 +03:00
2017-04-04 21:15:41 +03:00
for ( i = 0 ; i < vp_dev - > msix_vectors ; i + + )
if ( vp_dev - > msix_affinity_masks [ i ] )
2017-02-05 20:15:19 +03:00
free_cpumask_var ( vp_dev - > msix_affinity_masks [ i ] ) ;
2017-04-04 21:15:41 +03:00
if ( vp_dev - > msix_enabled ) {
2016-11-17 13:43:15 +03:00
/* Disable the vector used for configuration */
vp_dev - > config_vector ( vp_dev , VIRTIO_MSI_NO_VECTOR ) ;
2017-04-04 21:15:41 +03:00
pci_free_irq_vectors ( vp_dev - > pci_dev ) ;
vp_dev - > msix_enabled = 0 ;
2016-11-17 13:43:15 +03:00
}
2017-04-04 21:15:41 +03:00
vp_dev - > msix_vectors = 0 ;
vp_dev - > msix_used_vectors = 0 ;
kfree ( vp_dev - > msix_names ) ;
vp_dev - > msix_names = NULL ;
kfree ( vp_dev - > msix_affinity_masks ) ;
vp_dev - > msix_affinity_masks = NULL ;
2017-04-04 21:44:44 +03:00
kfree ( vp_dev - > vqs ) ;
vp_dev - > vqs = NULL ;
2009-06-13 08:16:36 +04:00
}
2016-11-17 13:43:16 +03:00
static int vp_find_vqs_msix ( struct virtio_device * vdev , unsigned nvqs ,
2017-02-05 20:15:21 +03:00
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
2017-04-04 21:08:54 +03:00
const char * const names [ ] , bool per_vq_vectors ,
2017-03-06 19:32:29 +03:00
const bool * ctx ,
2017-04-04 21:08:54 +03:00
struct irq_affinity * desc )
2009-06-13 08:16:36 +04:00
{
2009-07-26 16:48:08 +04:00
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2009-09-24 08:26:29 +04:00
u16 msix_vec ;
2017-04-04 21:15:41 +03:00
int i , err , nvectors , allocated_vectors ;
2009-05-14 14:55:41 +04:00
2017-04-04 21:44:44 +03:00
vp_dev - > vqs = kcalloc ( nvqs , sizeof ( * vp_dev - > vqs ) , GFP_KERNEL ) ;
if ( ! vp_dev - > vqs )
return - ENOMEM ;
2017-04-04 21:08:54 +03:00
if ( per_vq_vectors ) {
2017-04-04 21:15:41 +03:00
/* Best option: one for change interrupt, one per vq. */
nvectors = 1 ;
for ( i = 0 ; i < nvqs ; + + i )
if ( callbacks [ i ] )
+ + nvectors ;
2017-04-04 21:08:54 +03:00
} else {
2017-04-04 21:15:41 +03:00
/* Second best: one for change, shared for all vqs. */
nvectors = 2 ;
2017-02-05 20:15:19 +03:00
}
2017-04-04 21:15:41 +03:00
err = vp_request_msix_vectors ( vdev , nvectors , per_vq_vectors ,
per_vq_vectors ? desc : NULL ) ;
2016-11-17 13:43:16 +03:00
if ( err )
2017-04-04 21:15:41 +03:00
goto error_find ;
2016-11-17 13:43:16 +03:00
2017-04-04 21:44:44 +03:00
vp_dev - > per_vq_vectors = per_vq_vectors ;
2017-04-04 21:15:41 +03:00
allocated_vectors = vp_dev - > msix_used_vectors ;
2009-06-13 08:16:36 +04:00
for ( i = 0 ; i < nvqs ; + + i ) {
2012-09-05 22:47:45 +04:00
if ( ! names [ i ] ) {
vqs [ i ] = NULL ;
continue ;
2016-11-17 13:43:16 +03:00
}
2017-04-04 21:15:41 +03:00
if ( ! callbacks [ i ] )
2017-02-05 20:15:19 +03:00
msix_vec = VIRTIO_MSI_NO_VECTOR ;
2017-04-04 21:44:44 +03:00
else if ( vp_dev - > per_vq_vectors )
2017-04-04 21:15:41 +03:00
msix_vec = allocated_vectors + + ;
else
msix_vec = VP_MSIX_VQ_VECTOR ;
2017-04-04 21:44:44 +03:00
vqs [ i ] = vp_setup_vq ( vdev , i , callbacks [ i ] , names [ i ] ,
2017-03-06 19:32:29 +03:00
ctx ? ctx [ i ] : false ,
2017-04-04 21:44:44 +03:00
msix_vec ) ;
2009-07-26 16:48:08 +04:00
if ( IS_ERR ( vqs [ i ] ) ) {
err = PTR_ERR ( vqs [ i ] ) ;
2017-04-04 21:15:41 +03:00
goto error_find ;
2009-07-26 16:48:08 +04:00
}
2009-10-22 17:06:06 +04:00
2017-04-04 21:44:44 +03:00
if ( ! vp_dev - > per_vq_vectors | | msix_vec = = VIRTIO_MSI_NO_VECTOR )
2017-02-05 20:15:18 +03:00
continue ;
2017-04-04 21:15:41 +03:00
/* allocate per-vq irq if available and necessary */
snprintf ( vp_dev - > msix_names [ msix_vec ] ,
sizeof * vp_dev - > msix_names ,
" %s-%s " ,
2009-10-22 17:06:06 +04:00
dev_name ( & vp_dev - > vdev . dev ) , names [ i ] ) ;
2016-11-17 13:43:13 +03:00
err = request_irq ( pci_irq_vector ( vp_dev - > pci_dev , msix_vec ) ,
2017-04-04 21:15:41 +03:00
vring_interrupt , 0 ,
vp_dev - > msix_names [ msix_vec ] ,
vqs [ i ] ) ;
2017-04-04 21:44:44 +03:00
if ( err )
2017-04-04 21:15:41 +03:00
goto error_find ;
2009-06-13 08:16:36 +04:00
}
return 0 ;
2017-04-04 21:15:41 +03:00
error_find :
vp_del_vqs ( vdev ) ;
2009-07-26 16:48:08 +04:00
return err ;
}
2016-11-17 13:43:16 +03:00
static int vp_find_vqs_intx ( struct virtio_device * vdev , unsigned nvqs ,
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
2017-03-06 19:32:29 +03:00
const char * const names [ ] , const bool * ctx )
2016-11-17 13:43:16 +03:00
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
int i , err ;
2017-04-04 21:44:44 +03:00
vp_dev - > vqs = kcalloc ( nvqs , sizeof ( * vp_dev - > vqs ) , GFP_KERNEL ) ;
if ( ! vp_dev - > vqs )
return - ENOMEM ;
2016-11-17 13:43:16 +03:00
err = request_irq ( vp_dev - > pci_dev - > irq , vp_interrupt , IRQF_SHARED ,
dev_name ( & vdev - > dev ) , vp_dev ) ;
if ( err )
2017-04-04 21:15:41 +03:00
goto out_del_vqs ;
2016-11-17 13:43:16 +03:00
2017-04-04 21:15:41 +03:00
vp_dev - > intx_enabled = 1 ;
2017-04-04 21:44:44 +03:00
vp_dev - > per_vq_vectors = false ;
2016-11-17 13:43:16 +03:00
for ( i = 0 ; i < nvqs ; + + i ) {
if ( ! names [ i ] ) {
vqs [ i ] = NULL ;
continue ;
}
2017-04-04 21:44:44 +03:00
vqs [ i ] = vp_setup_vq ( vdev , i , callbacks [ i ] , names [ i ] ,
2017-03-06 19:32:29 +03:00
ctx ? ctx [ i ] : false ,
2017-04-04 21:44:44 +03:00
VIRTIO_MSI_NO_VECTOR ) ;
2016-11-17 13:43:16 +03:00
if ( IS_ERR ( vqs [ i ] ) ) {
err = PTR_ERR ( vqs [ i ] ) ;
2017-04-04 21:15:41 +03:00
goto out_del_vqs ;
2016-11-17 13:43:16 +03:00
}
}
return 0 ;
2017-04-04 21:15:41 +03:00
out_del_vqs :
vp_del_vqs ( vdev ) ;
2016-11-17 13:43:16 +03:00
return err ;
}
2009-07-26 16:48:08 +04:00
/* the config->find_vqs() implementation */
2014-12-07 19:41:16 +03:00
int vp_find_vqs ( struct virtio_device * vdev , unsigned nvqs ,
2017-02-05 20:15:22 +03:00
struct virtqueue * vqs [ ] , vq_callback_t * callbacks [ ] ,
2017-03-06 19:32:29 +03:00
const char * const names [ ] , const bool * ctx ,
struct irq_affinity * desc )
2009-07-26 16:48:08 +04:00
{
2009-09-24 08:26:29 +04:00
int err ;
2009-07-26 16:48:08 +04:00
2017-04-04 21:08:54 +03:00
/* Try MSI-X with one vector per queue. */
2017-03-06 19:32:29 +03:00
err = vp_find_vqs_msix ( vdev , nvqs , vqs , callbacks , names , true , ctx , desc ) ;
2017-04-04 21:08:54 +03:00
if ( ! err )
return 0 ;
/* Fallback: MSI-X with one vector for config, one shared for queues. */
2017-03-06 19:32:29 +03:00
err = vp_find_vqs_msix ( vdev , nvqs , vqs , callbacks , names , false , ctx , desc ) ;
2009-07-26 16:48:08 +04:00
if ( ! err )
return 0 ;
2017-04-04 21:08:54 +03:00
/* Finally fall back to regular interrupts. */
2017-03-06 19:32:29 +03:00
return vp_find_vqs_intx ( vdev , nvqs , vqs , callbacks , names , ctx ) ;
2009-06-13 08:16:36 +04:00
}
2014-12-07 19:41:16 +03:00
const char * vp_bus_name ( struct virtio_device * vdev )
2011-11-14 18:17:08 +04:00
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
return pci_name ( vp_dev - > pci_dev ) ;
}
2012-08-28 15:54:14 +04: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 19:41:16 +03:00
int vp_set_vq_affinity ( struct virtqueue * vq , int cpu )
2012-08-28 15:54:14 +04:00
{
struct virtio_device * vdev = vq - > vdev ;
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2017-04-04 21:44:44 +03:00
struct virtio_pci_vq_info * info = vp_dev - > vqs [ vq - > index ] ;
struct cpumask * mask ;
unsigned int irq ;
2012-08-28 15:54:14 +04:00
if ( ! vq - > callback )
return - EINVAL ;
2017-04-04 21:09:20 +03:00
if ( vp_dev - > msix_enabled ) {
2017-04-04 21:44:44 +03:00
mask = vp_dev - > msix_affinity_masks [ info - > msix_vector ] ;
irq = pci_irq_vector ( vp_dev - > pci_dev , info - > msix_vector ) ;
2012-08-28 15:54:14 +04:00
if ( cpu = = - 1 )
irq_set_affinity_hint ( irq , NULL ) ;
else {
2015-06-04 11:41:44 +03:00
cpumask_clear ( mask ) ;
2012-08-28 15:54:14 +04:00
cpumask_set_cpu ( cpu , mask ) ;
irq_set_affinity_hint ( irq , mask ) ;
}
}
return 0 ;
}
2017-02-05 20:15:23 +03:00
const struct cpumask * vp_get_vq_affinity ( struct virtio_device * vdev , int index )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
2017-04-04 21:44:44 +03:00
if ( ! vp_dev - > per_vq_vectors | |
vp_dev - > vqs [ index ] - > msix_vector = = VIRTIO_MSI_NO_VECTOR )
2017-02-05 20:15:23 +03:00
return NULL ;
2017-04-04 21:44:44 +03:00
return pci_irq_get_affinity ( vp_dev - > pci_dev ,
vp_dev - > vqs [ index ] - > msix_vector ) ;
2017-02-05 20:15:23 +03:00
}
2013-09-09 04:27:12 +04:00
# ifdef CONFIG_PM_SLEEP
2011-12-22 15:28:26 +04:00
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 04:10:35 +04:00
ret = virtio_device_freeze ( & vp_dev - > vdev ) ;
2011-12-22 15:28:26 +04:00
if ( ! ret )
pci_disable_device ( pci_dev ) ;
return ret ;
}
2012-03-29 11:24:43 +04:00
static int virtio_pci_restore ( struct device * dev )
2011-12-22 15:28:26 +04:00
{
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 11:24:43 +04:00
2011-12-22 15:28:26 +04:00
pci_set_master ( pci_dev ) ;
2014-10-14 04:10:35 +04:00
return virtio_device_restore ( & vp_dev - > vdev ) ;
2011-12-22 15:28:26 +04:00
}
2014-12-11 22:47:49 +03:00
static const struct dev_pm_ops virtio_pci_pm_ops = {
2012-03-29 11:28:05 +04:00
SET_SYSTEM_SLEEP_PM_OPS ( virtio_pci_freeze , virtio_pci_restore )
2011-12-22 15:28:25 +04:00
} ;
2007-11-13 06:30:26 +03:00
# endif
2014-12-11 22:47:49 +03:00
/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
static const struct pci_device_id virtio_pci_id_table [ ] = {
2016-03-07 01:02:30 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_REDHAT_QUMRANET , PCI_ANY_ID ) } ,
2014-12-11 22:47:49 +03:00
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , virtio_pci_id_table ) ;
2015-01-13 12:23:32 +03: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 22:47:49 +03:00
static int virtio_pci_probe ( struct pci_dev * pci_dev ,
const struct pci_device_id * id )
{
2017-12-21 15:40:24 +03:00
struct virtio_pci_device * vp_dev , * reg_dev = NULL ;
2015-01-13 12:23:32 +03:00
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 ;
2017-04-04 21:44:44 +03:00
INIT_LIST_HEAD ( & vp_dev - > virtqueues ) ;
spin_lock_init ( & vp_dev - > lock ) ;
2015-01-13 12:23:32 +03:00
/* enable the device */
rc = pci_enable_device ( pci_dev ) ;
if ( rc )
goto err_enable_device ;
2015-01-15 18:54:13 +03:00
if ( force_legacy ) {
2014-12-11 14:59:51 +03:00
rc = virtio_pci_legacy_probe ( vp_dev ) ;
2015-01-15 18:54:13 +03: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 12:23:32 +03:00
pci_set_master ( pci_dev ) ;
rc = register_virtio_device ( & vp_dev - > vdev ) ;
2017-12-21 15:40:24 +03:00
reg_dev = vp_dev ;
2015-01-13 12:23:32 +03:00
if ( rc )
goto err_register ;
return 0 ;
err_register :
2014-12-11 14:59:51 +03:00
if ( vp_dev - > ioaddr )
virtio_pci_legacy_remove ( vp_dev ) ;
else
virtio_pci_modern_remove ( vp_dev ) ;
2015-01-13 12:23:32 +03:00
err_probe :
pci_disable_device ( pci_dev ) ;
err_enable_device :
2017-12-21 15:40:24 +03:00
if ( reg_dev )
put_device ( & vp_dev - > vdev . dev ) ;
else
kfree ( vp_dev ) ;
2015-01-13 12:23:32 +03:00
return rc ;
2014-12-11 22:47:49 +03:00
}
static void virtio_pci_remove ( struct pci_dev * pci_dev )
{
2015-01-13 12:23:32 +03:00
struct virtio_pci_device * vp_dev = pci_get_drvdata ( pci_dev ) ;
2016-01-14 17:00:41 +03:00
struct device * dev = get_device ( & vp_dev - > vdev . dev ) ;
2015-01-13 12:23:32 +03:00
2018-06-01 07:02:39 +03:00
pci_disable_sriov ( pci_dev ) ;
2015-01-13 12:23:32 +03:00
unregister_virtio_device ( & vp_dev - > vdev ) ;
2014-12-11 14:59:51 +03:00
if ( vp_dev - > ioaddr )
virtio_pci_legacy_remove ( vp_dev ) ;
else
virtio_pci_modern_remove ( vp_dev ) ;
2015-01-13 12:23:32 +03:00
pci_disable_device ( pci_dev ) ;
2016-01-14 17:00:41 +03:00
put_device ( dev ) ;
2014-12-11 22:47:49 +03:00
}
2018-06-01 07:02:39 +03:00
static int virtio_pci_sriov_configure ( struct pci_dev * pci_dev , int num_vfs )
{
struct virtio_pci_device * vp_dev = pci_get_drvdata ( pci_dev ) ;
struct virtio_device * vdev = & vp_dev - > vdev ;
int ret ;
if ( ! ( vdev - > config - > get_status ( vdev ) & VIRTIO_CONFIG_S_DRIVER_OK ) )
return - EBUSY ;
if ( ! __virtio_test_bit ( vdev , VIRTIO_F_SR_IOV ) )
return - EINVAL ;
if ( pci_vfs_assigned ( pci_dev ) )
return - EPERM ;
if ( num_vfs = = 0 ) {
pci_disable_sriov ( pci_dev ) ;
return 0 ;
}
ret = pci_enable_sriov ( pci_dev , num_vfs ) ;
if ( ret < 0 )
return ret ;
return num_vfs ;
}
2014-12-11 22:47:49 +03: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
2018-06-01 07:02:39 +03:00
. sriov_configure = virtio_pci_sriov_configure ,
2014-12-11 22:47:49 +03:00
} ;
module_pci_driver ( virtio_pci_driver ) ;
2014-12-17 01:54:03 +03:00
MODULE_AUTHOR ( " Anthony Liguori <aliguori@us.ibm.com> " ) ;
MODULE_DESCRIPTION ( " virtio-pci " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( " 1 " ) ;