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