4f0fc22534
Improve the size of the virtio_pci_device structure, which is commonly used to represent a virtio PCI device. A given virtio PCI device can either of legacy type or modern type, with the struct virtio_pci_legacy_device occupying 32 bytes and the struct virtio_pci_modern_device occupying 88 bytes. Make them a union, thereby save 32 bytes of memory as shown by the pahole tool. This improvement is particularly beneficial when dealing with numerous devices, as it helps conserve memory resources. Before the modification, pahole tool reported the following: struct virtio_pci_device { [...] struct virtio_pci_legacy_device ldev; /* 824 32 */ /* --- cacheline 13 boundary (832 bytes) was 24 bytes ago --- */ struct virtio_pci_modern_device mdev; /* 856 88 */ /* XXX last struct has 4 bytes of padding */ [...] /* size: 1056, cachelines: 17, members: 19 */ [...] }; After the modification, pahole tool reported the following: struct virtio_pci_device { [...] union { struct virtio_pci_legacy_device ldev; /* 824 32 */ struct virtio_pci_modern_device mdev; /* 824 88 */ }; /* 824 88 */ [...] /* size: 1024, cachelines: 16, members: 18 */ [...] }; Signed-off-by: Feng Liu <feliu@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Message-Id: <20230516135446.16266-1-feliu@nvidia.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Acked-by: Jason Wang <jasowang@redhat.com>
143 lines
4.1 KiB
C
143 lines
4.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#ifndef _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H
|
|
#define _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H
|
|
/*
|
|
* Virtio PCI driver - APIs for common functionality for all device versions
|
|
*
|
|
* 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
|
|
* Copyright Red Hat, Inc. 2014
|
|
*
|
|
* Authors:
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
* Rusty Russell <rusty@rustcorp.com.au>
|
|
* Michael S. Tsirkin <mst@redhat.com>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/list.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/virtio.h>
|
|
#include <linux/virtio_config.h>
|
|
#include <linux/virtio_ring.h>
|
|
#include <linux/virtio_pci.h>
|
|
#include <linux/virtio_pci_legacy.h>
|
|
#include <linux/virtio_pci_modern.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
struct virtio_pci_vq_info {
|
|
/* the actual virtqueue */
|
|
struct virtqueue *vq;
|
|
|
|
/* the list node for the virtqueues list */
|
|
struct list_head node;
|
|
|
|
/* MSI-X vector (or none) */
|
|
unsigned int msix_vector;
|
|
};
|
|
|
|
/* Our device structure */
|
|
struct virtio_pci_device {
|
|
struct virtio_device vdev;
|
|
struct pci_dev *pci_dev;
|
|
union {
|
|
struct virtio_pci_legacy_device ldev;
|
|
struct virtio_pci_modern_device mdev;
|
|
};
|
|
bool is_legacy;
|
|
|
|
/* Where to read and clear interrupt */
|
|
u8 __iomem *isr;
|
|
|
|
/* a list of queues so we can dispatch IRQs */
|
|
spinlock_t lock;
|
|
struct list_head virtqueues;
|
|
|
|
/* array of all queues for house-keeping */
|
|
struct virtio_pci_vq_info **vqs;
|
|
|
|
/* MSI-X support */
|
|
int msix_enabled;
|
|
int intx_enabled;
|
|
cpumask_var_t *msix_affinity_masks;
|
|
/* Name strings for interrupts. This size should be enough,
|
|
* and I'm too lazy to allocate each name separately. */
|
|
char (*msix_names)[256];
|
|
/* Number of available vectors */
|
|
unsigned int msix_vectors;
|
|
/* Vectors allocated, excluding per-vq vectors if any */
|
|
unsigned int msix_used_vectors;
|
|
|
|
/* Whether we have vector per vq */
|
|
bool per_vq_vectors;
|
|
|
|
struct virtqueue *(*setup_vq)(struct virtio_pci_device *vp_dev,
|
|
struct virtio_pci_vq_info *info,
|
|
unsigned int idx,
|
|
void (*callback)(struct virtqueue *vq),
|
|
const char *name,
|
|
bool ctx,
|
|
u16 msix_vec);
|
|
void (*del_vq)(struct virtio_pci_vq_info *info);
|
|
|
|
u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector);
|
|
};
|
|
|
|
/* Constants for MSI-X */
|
|
/* Use first vector for configuration changes, second and the rest for
|
|
* virtqueues Thus, we need at least 2 vectors for MSI. */
|
|
enum {
|
|
VP_MSIX_CONFIG_VECTOR = 0,
|
|
VP_MSIX_VQ_VECTOR = 1,
|
|
};
|
|
|
|
/* Convert a generic virtio device to our structure */
|
|
static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
|
|
{
|
|
return container_of(vdev, struct virtio_pci_device, vdev);
|
|
}
|
|
|
|
/* wait for pending irq handlers */
|
|
void vp_synchronize_vectors(struct virtio_device *vdev);
|
|
/* the notify function used when creating a virt queue */
|
|
bool vp_notify(struct virtqueue *vq);
|
|
/* the config->del_vqs() implementation */
|
|
void vp_del_vqs(struct virtio_device *vdev);
|
|
/* the config->find_vqs() implementation */
|
|
int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
|
|
struct virtqueue *vqs[], vq_callback_t *callbacks[],
|
|
const char * const names[], const bool *ctx,
|
|
struct irq_affinity *desc);
|
|
const char *vp_bus_name(struct virtio_device *vdev);
|
|
|
|
/* 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
|
|
*/
|
|
int vp_set_vq_affinity(struct virtqueue *vq, const struct cpumask *cpu_mask);
|
|
|
|
const struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index);
|
|
|
|
#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
|
|
int virtio_pci_legacy_probe(struct virtio_pci_device *);
|
|
void virtio_pci_legacy_remove(struct virtio_pci_device *);
|
|
#else
|
|
static inline int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev)
|
|
{
|
|
return -ENODEV;
|
|
}
|
|
static inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev)
|
|
{
|
|
}
|
|
#endif
|
|
int virtio_pci_modern_probe(struct virtio_pci_device *);
|
|
void virtio_pci_modern_remove(struct virtio_pci_device *);
|
|
|
|
#endif
|