linux/drivers/pci/controller/vmd.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Volume Management Device driver
 * Copyright (c) 2015, Intel Corporation.
 */

#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/srcu.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>

#include <asm/irqdomain.h>

#define VMD_CFGBAR
#define VMD_MEMBAR1
#define VMD_MEMBAR2

#define PCI_REG_VMCAP
#define BUS_RESTRICT_CAP(vmcap)
#define PCI_REG_VMCONFIG
#define BUS_RESTRICT_CFG(vmcfg)
#define VMCONFIG_MSI_REMAP
#define PCI_REG_VMLOCK
#define MB2_SHADOW_EN(vmlock)

#define MB2_SHADOW_OFFSET
#define MB2_SHADOW_SIZE

enum vmd_features {};

#define VMD_BIOS_PM_QUIRK_LTR

#define VMD_FEATS_CLIENT

static DEFINE_IDA(vmd_instance_ida);

/*
 * Lock for manipulating VMD IRQ lists.
 */
static DEFINE_RAW_SPINLOCK(list_lock);

/**
 * struct vmd_irq - private data to map driver IRQ to the VMD shared vector
 * @node:	list item for parent traversal.
 * @irq:	back pointer to parent.
 * @enabled:	true if driver enabled IRQ
 * @virq:	the virtual IRQ value provided to the requesting driver.
 *
 * Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to
 * a VMD IRQ using this structure.
 */
struct vmd_irq {};

/**
 * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector
 * @irq_list:	the list of irq's the VMD one demuxes to.
 * @srcu:	SRCU struct for local synchronization.
 * @count:	number of child IRQs assigned to this vector; used to track
 *		sharing.
 * @virq:	The underlying VMD Linux interrupt number
 */
struct vmd_irq_list {};

struct vmd_dev {};

static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
{}

static inline unsigned int index_from_irqs(struct vmd_dev *vmd,
					   struct vmd_irq_list *irqs)
{}

/*
 * Drivers managing a device in a VMD domain allocate their own IRQs as before,
 * but the MSI entry for the hardware it's driving will be programmed with a
 * destination ID for the VMD MSI-X table.  The VMD muxes interrupts in its
 * domain into one of its own, and the VMD driver de-muxes these for the
 * handlers sharing that VMD IRQ.  The vmd irq_domain provides the operations
 * and irq_chip to set this up.
 */
static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{}

/*
 * We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
 */
static void vmd_irq_enable(struct irq_data *data)
{}

static void vmd_irq_disable(struct irq_data *data)
{}

static struct irq_chip vmd_msi_controller =;

static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
				     msi_alloc_info_t *arg)
{}

/*
 * XXX: We can be even smarter selecting the best IRQ once we solve the
 * affinity problem.
 */
static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
{}

static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
			unsigned int virq, irq_hw_number_t hwirq,
			msi_alloc_info_t *arg)
{}

static void vmd_msi_free(struct irq_domain *domain,
			struct msi_domain_info *info, unsigned int virq)
{}

static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev,
			   int nvec, msi_alloc_info_t *arg)
{}

static void vmd_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
{}

static struct msi_domain_ops vmd_msi_domain_ops =;

static struct msi_domain_info vmd_msi_domain_info =;

static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
{}

static int vmd_create_irq_domain(struct vmd_dev *vmd)
{}

static void vmd_remove_irq_domain(struct vmd_dev *vmd)
{}

static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
				  unsigned int devfn, int reg, int len)
{}

/*
 * CPU may deadlock if config space is not serialized on some versions of this
 * hardware, so all config space access is done under a spinlock.
 */
static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
			int len, u32 *value)
{}

/*
 * VMD h/w converts non-posted config writes to posted memory writes. The
 * read-back in this function forces the completion so it returns only after
 * the config space was written, as expected.
 */
static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
			 int len, u32 value)
{}

static struct pci_ops vmd_ops =;

#ifdef CONFIG_ACPI
static struct acpi_device *vmd_acpi_find_companion(struct pci_dev *pci_dev)
{}

static bool hook_installed;

static void vmd_acpi_begin(void)
{}

static void vmd_acpi_end(void)
{}
#else
static inline void vmd_acpi_begin(void) { }
static inline void vmd_acpi_end(void) { }
#endif /* CONFIG_ACPI */

static void vmd_domain_reset(struct vmd_dev *vmd)
{}

static void vmd_attach_resources(struct vmd_dev *vmd)
{}

static void vmd_detach_resources(struct vmd_dev *vmd)
{}

/*
 * VMD domains start at 0x10000 to not clash with ACPI _SEG domains.
 * Per ACPI r6.0, sec 6.5.6,  _SEG returns an integer, of which the lower
 * 16 bits are the PCI Segment Group (domain) number.  Other bits are
 * currently reserved.
 */
static int vmd_find_free_domain(void)
{}

static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint,
				resource_size_t *offset1,
				resource_size_t *offset2)
{}

static int vmd_get_bus_number_start(struct vmd_dev *vmd)
{}

static irqreturn_t vmd_irq(int irq, void *data)
{}

static int vmd_alloc_irqs(struct vmd_dev *vmd)
{}

/*
 * Since VMD is an aperture to regular PCIe root ports, only allow it to
 * control features that the OS is allowed to control on the physical PCI bus.
 */
static void vmd_copy_host_bridge_flags(struct pci_host_bridge *root_bridge,
				       struct pci_host_bridge *vmd_bridge)
{}

/*
 * Enable ASPM and LTR settings on devices that aren't configured by BIOS.
 */
static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
{}

static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
{}

static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
{}

static void vmd_cleanup_srcu(struct vmd_dev *vmd)
{}

static void vmd_remove(struct pci_dev *dev)
{}

static void vmd_shutdown(struct pci_dev *dev)
{}

#ifdef CONFIG_PM_SLEEP
static int vmd_suspend(struct device *dev)
{}

static int vmd_resume(struct device *dev)
{}
#endif
static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);

static const struct pci_device_id vmd_ids[] =;
MODULE_DEVICE_TABLE(pci, vmd_ids);

static struct pci_driver vmd_drv =;
module_pci_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_VERSION();