2019-05-22 09:51:24 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-12-07 18:41:16 +02:00
/*
2014-12-08 12:31:02 +02:00
* Virtio PCI driver - legacy device support
2014-12-07 18:41:16 +02: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
2014-12-07 18:41:16 +02: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 >
2014-12-07 18:41:16 +02:00
*/
2021-10-29 17:14:42 +08:00
# include "linux/virtio_pci_legacy.h"
2014-12-08 16:39:45 +02:00
# include "virtio_pci_common.h"
2014-12-07 18:41:16 +02: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 . */
2021-10-29 17:14:42 +08:00
return vp_legacy_get_features ( & vp_dev - > ldev ) ;
2014-12-07 18:41:16 +02:00
}
/* 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. */
2021-10-29 17:14:42 +08:00
vp_legacy_set_features ( & vp_dev - > ldev , vdev - > features ) ;
2014-12-07 18:41:16 +02:00
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 ) ;
2021-10-29 17:14:42 +08:00
void __iomem * ioaddr = vp_dev - > ldev . ioaddr +
2018-12-10 08:54:34 +08:00
VIRTIO_PCI_CONFIG_OFF ( vp_dev - > msix_enabled ) +
offset ;
2014-12-07 18:41:16 +02:00
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 ) ;
2021-10-29 17:14:42 +08:00
void __iomem * ioaddr = vp_dev - > ldev . ioaddr +
2018-12-10 08:54:34 +08:00
VIRTIO_PCI_CONFIG_OFF ( vp_dev - > msix_enabled ) +
offset ;
2014-12-07 18:41:16 +02:00
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 ) ;
2021-10-29 17:14:42 +08:00
return vp_legacy_get_status ( & vp_dev - > ldev ) ;
2014-12-07 18:41:16 +02:00
}
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 ) ;
2021-10-29 17:14:42 +08:00
vp_legacy_set_status ( & vp_dev - > ldev , status ) ;
2014-12-07 18:41:16 +02:00
}
static void vp_reset ( struct virtio_device * vdev )
{
struct virtio_pci_device * vp_dev = to_vp_device ( vdev ) ;
/* 0 status means a reset. */
2021-10-29 17:14:42 +08:00
vp_legacy_set_status ( & vp_dev - > ldev , 0 ) ;
2014-12-07 18:41:16 +02:00
/* Flush out the status write, and flush in device writes,
* including MSi - X interrupts , if any . */
2021-10-29 17:14:42 +08:00
vp_legacy_get_status ( & vp_dev - > ldev ) ;
2021-10-19 15:01:46 +08:00
/* Disable VQ/configuration callbacks. */
vp_disable_cbs ( vdev ) ;
2014-12-07 18:41:16 +02:00
}
static u16 vp_config_vector ( struct virtio_pci_device * vp_dev , u16 vector )
{
2021-10-29 17:14:42 +08:00
return vp_legacy_config_vector ( & vp_dev - > ldev , vector ) ;
2014-12-07 18:41:16 +02:00
}
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 18:41:16 +02:00
unsigned index ,
void ( * callback ) ( struct virtqueue * vq ) ,
const char * name ,
2017-03-06 18:32:29 +02:00
bool ctx ,
2014-12-07 18:41:16 +02:00
u16 msix_vec )
{
struct virtqueue * vq ;
u16 num ;
int err ;
2018-07-18 10:18:45 +01:00
u64 q_pfn ;
2014-12-07 18:41:16 +02:00
/* Check if queue is either not available or already active. */
2021-10-29 17:14:42 +08:00
num = vp_legacy_get_queue_size ( & vp_dev - > ldev , index ) ;
if ( ! num | | vp_legacy_get_queue_enable ( & vp_dev - > ldev , index ) )
2014-12-07 18:41:16 +02:00
return ERR_PTR ( - ENOENT ) ;
2017-04-04 21:44:44 +03:00
info - > msix_vector = msix_vec ;
2016-02-02 21:46:39 -08:00
/* create the vring */
vq = vring_create_virtqueue ( index , num ,
VIRTIO_PCI_VRING_ALIGN , & vp_dev - > vdev ,
2017-03-06 18:32:29 +02:00
true , false , ctx ,
vp_notify , callback , name ) ;
2016-02-02 21:46:39 -08:00
if ( ! vq )
2014-12-07 18:41:16 +02:00
return ERR_PTR ( - ENOMEM ) ;
2018-07-18 10:18:45 +01:00
q_pfn = virtqueue_get_desc_addr ( vq ) > > VIRTIO_PCI_QUEUE_ADDR_SHIFT ;
if ( q_pfn > > 32 ) {
dev_err ( & vp_dev - > pci_dev - > dev ,
2021-12-09 11:29:25 +08:00
" platform bug: legacy virtio-pci must not be used with RAM above 0x%llxGB \n " ,
2018-07-18 10:18:45 +01:00
0x1ULL < < ( 32 + PAGE_SHIFT - 30 ) ) ;
err = - E2BIG ;
goto out_del_vq ;
}
2014-12-07 18:41:16 +02:00
/* activate the queue */
2021-10-29 17:14:42 +08:00
vp_legacy_set_queue_address ( & vp_dev - > ldev , index , q_pfn ) ;
2014-12-07 18:41:16 +02:00
2021-10-29 17:14:42 +08:00
vq - > priv = ( void __force * ) vp_dev - > ldev . ioaddr + VIRTIO_PCI_QUEUE_NOTIFY ;
2014-12-07 18:41:16 +02:00
if ( msix_vec ! = VIRTIO_MSI_NO_VECTOR ) {
2021-10-29 17:14:42 +08:00
msix_vec = vp_legacy_queue_vector ( & vp_dev - > ldev , index , msix_vec ) ;
2014-12-07 18:41:16 +02:00
if ( msix_vec = = VIRTIO_MSI_NO_VECTOR ) {
err = - EBUSY ;
2016-02-02 21:46:39 -08:00
goto out_deactivate ;
2014-12-07 18:41:16 +02:00
}
}
return vq ;
2016-02-02 21:46:39 -08:00
out_deactivate :
2021-10-29 17:14:42 +08:00
vp_legacy_set_queue_address ( & vp_dev - > ldev , index , 0 ) ;
2018-07-18 10:18:45 +01:00
out_del_vq :
2016-02-02 21:46:39 -08:00
vring_del_virtqueue ( vq ) ;
2014-12-07 18:41:16 +02: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 18:41:16 +02:00
{
2017-04-04 21:44:44 +03:00
struct virtqueue * vq = info - > vq ;
2014-12-07 18:41:16 +02:00
struct virtio_pci_device * vp_dev = to_vp_device ( vq - > vdev ) ;
2017-04-04 21:09:20 +03:00
if ( vp_dev - > msix_enabled ) {
2021-10-29 17:14:42 +08:00
vp_legacy_queue_vector ( & vp_dev - > ldev , vq - > index ,
VIRTIO_MSI_NO_VECTOR ) ;
2014-12-07 18:41:16 +02:00
/* Flush the write out to device */
2021-10-29 17:14:42 +08:00
ioread8 ( vp_dev - > ldev . ioaddr + VIRTIO_PCI_ISR ) ;
2014-12-07 18:41:16 +02:00
}
/* Select and deactivate the queue */
2021-10-29 17:14:42 +08:00
vp_legacy_set_queue_address ( & vp_dev - > ldev , vq - > index , 0 ) ;
2014-12-07 18:41:16 +02:00
2016-02-02 21:46:39 -08:00
vring_del_virtqueue ( vq ) ;
2014-12-07 18:41:16 +02:00
}
static const struct virtio_config_ops virtio_pci_config_ops = {
2021-10-19 15:01:46 +08:00
. enable_cbs = vp_enable_cbs ,
2014-12-07 18:41:16 +02:00
. 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 18:15:23 +01:00
. get_vq_affinity = vp_get_vq_affinity ,
2014-12-07 18:41:16 +02:00
} ;
/* the PCI probing function */
2015-01-13 11:23:32 +02:00
int virtio_pci_legacy_probe ( struct virtio_pci_device * vp_dev )
2014-12-07 18:41:16 +02:00
{
2021-10-29 17:14:42 +08:00
struct virtio_pci_legacy_device * ldev = & vp_dev - > ldev ;
2015-01-13 11:23:32 +02:00
struct pci_dev * pci_dev = vp_dev - > pci_dev ;
2015-06-24 07:54:15 +02:00
int rc ;
2014-12-07 18:41:16 +02:00
2021-10-29 17:14:42 +08:00
ldev - > pci_dev = pci_dev ;
2016-02-02 21:46:39 -08:00
2021-10-29 17:14:42 +08:00
rc = vp_legacy_probe ( ldev ) ;
2015-06-24 07:54:15 +02:00
if ( rc )
return rc ;
2021-10-29 17:14:42 +08:00
vp_dev - > isr = ldev - > isr ;
vp_dev - > vdev . id = ldev - > id ;
2014-12-07 18:41:16 +02:00
2015-01-13 11:23:32 +02:00
vp_dev - > vdev . config = & virtio_pci_config_ops ;
2014-12-07 18:41:16 +02:00
vp_dev - > config_vector = vp_config_vector ;
vp_dev - > setup_vq = setup_vq ;
vp_dev - > del_vq = del_vq ;
return 0 ;
}
2015-01-13 11:23:32 +02:00
void virtio_pci_legacy_remove ( struct virtio_pci_device * vp_dev )
2014-12-07 18:41:16 +02:00
{
2021-10-29 17:14:42 +08:00
struct virtio_pci_legacy_device * ldev = & vp_dev - > ldev ;
2014-12-07 18:41:16 +02:00
2021-10-29 17:14:42 +08:00
vp_legacy_remove ( ldev ) ;
2014-12-07 18:41:16 +02:00
}