cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

msi.c (10089B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Support of MSI, HPET and DMAR interrupts.
      4 *
      5 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
      6 *	Moved from arch/x86/kernel/apic/io_apic.c.
      7 * Jiang Liu <jiang.liu@linux.intel.com>
      8 *	Convert to hierarchical irqdomain
      9 */
     10#include <linux/mm.h>
     11#include <linux/interrupt.h>
     12#include <linux/irq.h>
     13#include <linux/pci.h>
     14#include <linux/dmar.h>
     15#include <linux/hpet.h>
     16#include <linux/msi.h>
     17#include <asm/irqdomain.h>
     18#include <asm/hpet.h>
     19#include <asm/hw_irq.h>
     20#include <asm/apic.h>
     21#include <asm/irq_remapping.h>
     22#include <asm/xen/hypervisor.h>
     23
     24struct irq_domain *x86_pci_msi_default_domain __ro_after_init;
     25
     26static void irq_msi_update_msg(struct irq_data *irqd, struct irq_cfg *cfg)
     27{
     28	struct msi_msg msg[2] = { [1] = { }, };
     29
     30	__irq_msi_compose_msg(cfg, msg, false);
     31	irq_data_get_irq_chip(irqd)->irq_write_msi_msg(irqd, msg);
     32}
     33
     34static int
     35msi_set_affinity(struct irq_data *irqd, const struct cpumask *mask, bool force)
     36{
     37	struct irq_cfg old_cfg, *cfg = irqd_cfg(irqd);
     38	struct irq_data *parent = irqd->parent_data;
     39	unsigned int cpu;
     40	int ret;
     41
     42	/* Save the current configuration */
     43	cpu = cpumask_first(irq_data_get_effective_affinity_mask(irqd));
     44	old_cfg = *cfg;
     45
     46	/* Allocate a new target vector */
     47	ret = parent->chip->irq_set_affinity(parent, mask, force);
     48	if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
     49		return ret;
     50
     51	/*
     52	 * For non-maskable and non-remapped MSI interrupts the migration
     53	 * to a different destination CPU and a different vector has to be
     54	 * done careful to handle the possible stray interrupt which can be
     55	 * caused by the non-atomic update of the address/data pair.
     56	 *
     57	 * Direct update is possible when:
     58	 * - The MSI is maskable (remapped MSI does not use this code path)).
     59	 *   The quirk bit is not set in this case.
     60	 * - The new vector is the same as the old vector
     61	 * - The old vector is MANAGED_IRQ_SHUTDOWN_VECTOR (interrupt starts up)
     62	 * - The interrupt is not yet started up
     63	 * - The new destination CPU is the same as the old destination CPU
     64	 */
     65	if (!irqd_msi_nomask_quirk(irqd) ||
     66	    cfg->vector == old_cfg.vector ||
     67	    old_cfg.vector == MANAGED_IRQ_SHUTDOWN_VECTOR ||
     68	    !irqd_is_started(irqd) ||
     69	    cfg->dest_apicid == old_cfg.dest_apicid) {
     70		irq_msi_update_msg(irqd, cfg);
     71		return ret;
     72	}
     73
     74	/*
     75	 * Paranoia: Validate that the interrupt target is the local
     76	 * CPU.
     77	 */
     78	if (WARN_ON_ONCE(cpu != smp_processor_id())) {
     79		irq_msi_update_msg(irqd, cfg);
     80		return ret;
     81	}
     82
     83	/*
     84	 * Redirect the interrupt to the new vector on the current CPU
     85	 * first. This might cause a spurious interrupt on this vector if
     86	 * the device raises an interrupt right between this update and the
     87	 * update to the final destination CPU.
     88	 *
     89	 * If the vector is in use then the installed device handler will
     90	 * denote it as spurious which is no harm as this is a rare event
     91	 * and interrupt handlers have to cope with spurious interrupts
     92	 * anyway. If the vector is unused, then it is marked so it won't
     93	 * trigger the 'No irq handler for vector' warning in
     94	 * common_interrupt().
     95	 *
     96	 * This requires to hold vector lock to prevent concurrent updates to
     97	 * the affected vector.
     98	 */
     99	lock_vector_lock();
    100
    101	/*
    102	 * Mark the new target vector on the local CPU if it is currently
    103	 * unused. Reuse the VECTOR_RETRIGGERED state which is also used in
    104	 * the CPU hotplug path for a similar purpose. This cannot be
    105	 * undone here as the current CPU has interrupts disabled and
    106	 * cannot handle the interrupt before the whole set_affinity()
    107	 * section is done. In the CPU unplug case, the current CPU is
    108	 * about to vanish and will not handle any interrupts anymore. The
    109	 * vector is cleaned up when the CPU comes online again.
    110	 */
    111	if (IS_ERR_OR_NULL(this_cpu_read(vector_irq[cfg->vector])))
    112		this_cpu_write(vector_irq[cfg->vector], VECTOR_RETRIGGERED);
    113
    114	/* Redirect it to the new vector on the local CPU temporarily */
    115	old_cfg.vector = cfg->vector;
    116	irq_msi_update_msg(irqd, &old_cfg);
    117
    118	/* Now transition it to the target CPU */
    119	irq_msi_update_msg(irqd, cfg);
    120
    121	/*
    122	 * All interrupts after this point are now targeted at the new
    123	 * vector/CPU.
    124	 *
    125	 * Drop vector lock before testing whether the temporary assignment
    126	 * to the local CPU was hit by an interrupt raised in the device,
    127	 * because the retrigger function acquires vector lock again.
    128	 */
    129	unlock_vector_lock();
    130
    131	/*
    132	 * Check whether the transition raced with a device interrupt and
    133	 * is pending in the local APICs IRR. It is safe to do this outside
    134	 * of vector lock as the irq_desc::lock of this interrupt is still
    135	 * held and interrupts are disabled: The check is not accessing the
    136	 * underlying vector store. It's just checking the local APIC's
    137	 * IRR.
    138	 */
    139	if (lapic_vector_set_in_irr(cfg->vector))
    140		irq_data_get_irq_chip(irqd)->irq_retrigger(irqd);
    141
    142	return ret;
    143}
    144
    145/*
    146 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
    147 * which implement the MSI or MSI-X Capability Structure.
    148 */
    149static struct irq_chip pci_msi_controller = {
    150	.name			= "PCI-MSI",
    151	.irq_unmask		= pci_msi_unmask_irq,
    152	.irq_mask		= pci_msi_mask_irq,
    153	.irq_ack		= irq_chip_ack_parent,
    154	.irq_retrigger		= irq_chip_retrigger_hierarchy,
    155	.irq_set_affinity	= msi_set_affinity,
    156	.flags			= IRQCHIP_SKIP_SET_WAKE |
    157				  IRQCHIP_AFFINITY_PRE_STARTUP,
    158};
    159
    160int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
    161		    msi_alloc_info_t *arg)
    162{
    163	init_irq_alloc_info(arg, NULL);
    164	if (to_pci_dev(dev)->msix_enabled) {
    165		arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSIX;
    166	} else {
    167		arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSI;
    168		arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
    169	}
    170
    171	return 0;
    172}
    173EXPORT_SYMBOL_GPL(pci_msi_prepare);
    174
    175static struct msi_domain_ops pci_msi_domain_ops = {
    176	.msi_prepare	= pci_msi_prepare,
    177};
    178
    179static struct msi_domain_info pci_msi_domain_info = {
    180	.flags		= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
    181			  MSI_FLAG_PCI_MSIX,
    182	.ops		= &pci_msi_domain_ops,
    183	.chip		= &pci_msi_controller,
    184	.handler	= handle_edge_irq,
    185	.handler_name	= "edge",
    186};
    187
    188struct irq_domain * __init native_create_pci_msi_domain(void)
    189{
    190	struct fwnode_handle *fn;
    191	struct irq_domain *d;
    192
    193	if (disable_apic)
    194		return NULL;
    195
    196	fn = irq_domain_alloc_named_fwnode("PCI-MSI");
    197	if (!fn)
    198		return NULL;
    199
    200	d = pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
    201				      x86_vector_domain);
    202	if (!d) {
    203		irq_domain_free_fwnode(fn);
    204		pr_warn("Failed to initialize PCI-MSI irqdomain.\n");
    205	} else {
    206		d->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK;
    207	}
    208	return d;
    209}
    210
    211void __init x86_create_pci_msi_domain(void)
    212{
    213	x86_pci_msi_default_domain = x86_init.irqs.create_pci_msi_domain();
    214}
    215
    216#ifdef CONFIG_IRQ_REMAP
    217static struct irq_chip pci_msi_ir_controller = {
    218	.name			= "IR-PCI-MSI",
    219	.irq_unmask		= pci_msi_unmask_irq,
    220	.irq_mask		= pci_msi_mask_irq,
    221	.irq_ack		= irq_chip_ack_parent,
    222	.irq_retrigger		= irq_chip_retrigger_hierarchy,
    223	.flags			= IRQCHIP_SKIP_SET_WAKE |
    224				  IRQCHIP_AFFINITY_PRE_STARTUP,
    225};
    226
    227static struct msi_domain_info pci_msi_ir_domain_info = {
    228	.flags		= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
    229			  MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
    230	.ops		= &pci_msi_domain_ops,
    231	.chip		= &pci_msi_ir_controller,
    232	.handler	= handle_edge_irq,
    233	.handler_name	= "edge",
    234};
    235
    236struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
    237						    const char *name, int id)
    238{
    239	struct fwnode_handle *fn;
    240	struct irq_domain *d;
    241
    242	fn = irq_domain_alloc_named_id_fwnode(name, id);
    243	if (!fn)
    244		return NULL;
    245	d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
    246	if (!d)
    247		irq_domain_free_fwnode(fn);
    248	return d;
    249}
    250#endif
    251
    252#ifdef CONFIG_DMAR_TABLE
    253/*
    254 * The Intel IOMMU (ab)uses the high bits of the MSI address to contain the
    255 * high bits of the destination APIC ID. This can't be done in the general
    256 * case for MSIs as it would be targeting real memory above 4GiB not the
    257 * APIC.
    258 */
    259static void dmar_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
    260{
    261	__irq_msi_compose_msg(irqd_cfg(data), msg, true);
    262}
    263
    264static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
    265{
    266	dmar_msi_write(data->irq, msg);
    267}
    268
    269static struct irq_chip dmar_msi_controller = {
    270	.name			= "DMAR-MSI",
    271	.irq_unmask		= dmar_msi_unmask,
    272	.irq_mask		= dmar_msi_mask,
    273	.irq_ack		= irq_chip_ack_parent,
    274	.irq_set_affinity	= msi_domain_set_affinity,
    275	.irq_retrigger		= irq_chip_retrigger_hierarchy,
    276	.irq_compose_msi_msg	= dmar_msi_compose_msg,
    277	.irq_write_msi_msg	= dmar_msi_write_msg,
    278	.flags			= IRQCHIP_SKIP_SET_WAKE |
    279				  IRQCHIP_AFFINITY_PRE_STARTUP,
    280};
    281
    282static int dmar_msi_init(struct irq_domain *domain,
    283			 struct msi_domain_info *info, unsigned int virq,
    284			 irq_hw_number_t hwirq, msi_alloc_info_t *arg)
    285{
    286	irq_domain_set_info(domain, virq, arg->devid, info->chip, NULL,
    287			    handle_edge_irq, arg->data, "edge");
    288
    289	return 0;
    290}
    291
    292static struct msi_domain_ops dmar_msi_domain_ops = {
    293	.msi_init	= dmar_msi_init,
    294};
    295
    296static struct msi_domain_info dmar_msi_domain_info = {
    297	.ops		= &dmar_msi_domain_ops,
    298	.chip		= &dmar_msi_controller,
    299	.flags		= MSI_FLAG_USE_DEF_DOM_OPS,
    300};
    301
    302static struct irq_domain *dmar_get_irq_domain(void)
    303{
    304	static struct irq_domain *dmar_domain;
    305	static DEFINE_MUTEX(dmar_lock);
    306	struct fwnode_handle *fn;
    307
    308	mutex_lock(&dmar_lock);
    309	if (dmar_domain)
    310		goto out;
    311
    312	fn = irq_domain_alloc_named_fwnode("DMAR-MSI");
    313	if (fn) {
    314		dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info,
    315						    x86_vector_domain);
    316		if (!dmar_domain)
    317			irq_domain_free_fwnode(fn);
    318	}
    319out:
    320	mutex_unlock(&dmar_lock);
    321	return dmar_domain;
    322}
    323
    324int dmar_alloc_hwirq(int id, int node, void *arg)
    325{
    326	struct irq_domain *domain = dmar_get_irq_domain();
    327	struct irq_alloc_info info;
    328
    329	if (!domain)
    330		return -1;
    331
    332	init_irq_alloc_info(&info, NULL);
    333	info.type = X86_IRQ_ALLOC_TYPE_DMAR;
    334	info.devid = id;
    335	info.hwirq = id;
    336	info.data = arg;
    337
    338	return irq_domain_alloc_irqs(domain, 1, node, &info);
    339}
    340
    341void dmar_free_hwirq(int irq)
    342{
    343	irq_domain_free_irqs(irq, 1);
    344}
    345#endif
    346
    347bool arch_restore_msi_irqs(struct pci_dev *dev)
    348{
    349	return xen_initdom_restore_msi(dev);
    350}