162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci#ifndef _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H 362306a36Sopenharmony_ci#define _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * Virtio PCI driver - APIs for common functionality for all device versions 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This module allows virtio devices to be used over a virtual PCI device. 862306a36Sopenharmony_ci * This can be used with QEMU based VMMs like KVM or Xen. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright IBM Corp. 2007 1162306a36Sopenharmony_ci * Copyright Red Hat, Inc. 2014 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Authors: 1462306a36Sopenharmony_ci * Anthony Liguori <aliguori@us.ibm.com> 1562306a36Sopenharmony_ci * Rusty Russell <rusty@rustcorp.com.au> 1662306a36Sopenharmony_ci * Michael S. Tsirkin <mst@redhat.com> 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/list.h> 2162306a36Sopenharmony_ci#include <linux/pci.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/virtio.h> 2562306a36Sopenharmony_ci#include <linux/virtio_config.h> 2662306a36Sopenharmony_ci#include <linux/virtio_ring.h> 2762306a36Sopenharmony_ci#include <linux/virtio_pci.h> 2862306a36Sopenharmony_ci#include <linux/virtio_pci_legacy.h> 2962306a36Sopenharmony_ci#include <linux/virtio_pci_modern.h> 3062306a36Sopenharmony_ci#include <linux/highmem.h> 3162306a36Sopenharmony_ci#include <linux/spinlock.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct virtio_pci_vq_info { 3462306a36Sopenharmony_ci /* the actual virtqueue */ 3562306a36Sopenharmony_ci struct virtqueue *vq; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* the list node for the virtqueues list */ 3862306a36Sopenharmony_ci struct list_head node; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* MSI-X vector (or none) */ 4162306a36Sopenharmony_ci unsigned int msix_vector; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Our device structure */ 4562306a36Sopenharmony_cistruct virtio_pci_device { 4662306a36Sopenharmony_ci struct virtio_device vdev; 4762306a36Sopenharmony_ci struct pci_dev *pci_dev; 4862306a36Sopenharmony_ci union { 4962306a36Sopenharmony_ci struct virtio_pci_legacy_device ldev; 5062306a36Sopenharmony_ci struct virtio_pci_modern_device mdev; 5162306a36Sopenharmony_ci }; 5262306a36Sopenharmony_ci bool is_legacy; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Where to read and clear interrupt */ 5562306a36Sopenharmony_ci u8 __iomem *isr; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* a list of queues so we can dispatch IRQs */ 5862306a36Sopenharmony_ci spinlock_t lock; 5962306a36Sopenharmony_ci struct list_head virtqueues; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* array of all queues for house-keeping */ 6262306a36Sopenharmony_ci struct virtio_pci_vq_info **vqs; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* MSI-X support */ 6562306a36Sopenharmony_ci int msix_enabled; 6662306a36Sopenharmony_ci int intx_enabled; 6762306a36Sopenharmony_ci cpumask_var_t *msix_affinity_masks; 6862306a36Sopenharmony_ci /* Name strings for interrupts. This size should be enough, 6962306a36Sopenharmony_ci * and I'm too lazy to allocate each name separately. */ 7062306a36Sopenharmony_ci char (*msix_names)[256]; 7162306a36Sopenharmony_ci /* Number of available vectors */ 7262306a36Sopenharmony_ci unsigned int msix_vectors; 7362306a36Sopenharmony_ci /* Vectors allocated, excluding per-vq vectors if any */ 7462306a36Sopenharmony_ci unsigned int msix_used_vectors; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* Whether we have vector per vq */ 7762306a36Sopenharmony_ci bool per_vq_vectors; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci struct virtqueue *(*setup_vq)(struct virtio_pci_device *vp_dev, 8062306a36Sopenharmony_ci struct virtio_pci_vq_info *info, 8162306a36Sopenharmony_ci unsigned int idx, 8262306a36Sopenharmony_ci void (*callback)(struct virtqueue *vq), 8362306a36Sopenharmony_ci const char *name, 8462306a36Sopenharmony_ci bool ctx, 8562306a36Sopenharmony_ci u16 msix_vec); 8662306a36Sopenharmony_ci void (*del_vq)(struct virtio_pci_vq_info *info); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector); 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Constants for MSI-X */ 9262306a36Sopenharmony_ci/* Use first vector for configuration changes, second and the rest for 9362306a36Sopenharmony_ci * virtqueues Thus, we need at least 2 vectors for MSI. */ 9462306a36Sopenharmony_cienum { 9562306a36Sopenharmony_ci VP_MSIX_CONFIG_VECTOR = 0, 9662306a36Sopenharmony_ci VP_MSIX_VQ_VECTOR = 1, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* Convert a generic virtio device to our structure */ 10062306a36Sopenharmony_cistatic struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return container_of(vdev, struct virtio_pci_device, vdev); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* wait for pending irq handlers */ 10662306a36Sopenharmony_civoid vp_synchronize_vectors(struct virtio_device *vdev); 10762306a36Sopenharmony_ci/* the notify function used when creating a virt queue */ 10862306a36Sopenharmony_cibool vp_notify(struct virtqueue *vq); 10962306a36Sopenharmony_ci/* the config->del_vqs() implementation */ 11062306a36Sopenharmony_civoid vp_del_vqs(struct virtio_device *vdev); 11162306a36Sopenharmony_ci/* the config->find_vqs() implementation */ 11262306a36Sopenharmony_ciint vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs, 11362306a36Sopenharmony_ci struct virtqueue *vqs[], vq_callback_t *callbacks[], 11462306a36Sopenharmony_ci const char * const names[], const bool *ctx, 11562306a36Sopenharmony_ci struct irq_affinity *desc); 11662306a36Sopenharmony_ciconst char *vp_bus_name(struct virtio_device *vdev); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Setup the affinity for a virtqueue: 11962306a36Sopenharmony_ci * - force the affinity for per vq vector 12062306a36Sopenharmony_ci * - OR over all affinities for shared MSI 12162306a36Sopenharmony_ci * - ignore the affinity request if we're using INTX 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ciint vp_set_vq_affinity(struct virtqueue *vq, const struct cpumask *cpu_mask); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciconst struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY) 12862306a36Sopenharmony_ciint virtio_pci_legacy_probe(struct virtio_pci_device *); 12962306a36Sopenharmony_civoid virtio_pci_legacy_remove(struct virtio_pci_device *); 13062306a36Sopenharmony_ci#else 13162306a36Sopenharmony_cistatic inline int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci return -ENODEV; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_cistatic inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ciint virtio_pci_modern_probe(struct virtio_pci_device *); 14062306a36Sopenharmony_civoid virtio_pci_modern_remove(struct virtio_pci_device *); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#endif 143