Blob Blame History Raw
Subject: hyperv: set nvme msi interrupts to unmanaged
From: Olaf Hering <ohering@suse.de>
Patch-mainline: Never, stale kernel
References: jsc#SLE-8953, jsc#SLE-9221, jsc#SLE-4941, bsc#1119461, bsc#1119465, bsc#1138190, bsc#1154905

Needs a matching irqbalance.rpm

--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/sed-opal.h>
+#include <linux/msi.h>
 
 #include "nvme.h"
 
@@ -1970,6 +1971,10 @@ static int nvme_setup_io_queues(struct n
 	dev->num_vecs = result;
 	dev->max_qid = max(result - 1, 1);
 
+#ifdef CONFIG_GENERIC_MSI_IRQ
+	suse_msi_set_irq_unmanaged(dev->dev);
+#endif
+
 	/*
 	 * Should investigate if there's a performance win from allocating
 	 * more queues than interrupt vectors; it might allow the submission
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -18,6 +18,7 @@ struct pci_dev;
 struct platform_msi_priv_data;
 void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 #ifdef CONFIG_GENERIC_MSI_IRQ
+int suse_msi_set_irq_unmanaged(struct device *dev);
 void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
 #else
 static inline void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -15,6 +15,45 @@
 #include <linux/irqdomain.h>
 #include <linux/msi.h>
 #include <linux/slab.h>
+#if IS_ENABLED(CONFIG_HYPERV)
+#ifndef __GENKSYMS__
+#include "internals.h"
+#include <asm/hypervisor.h>
+#endif
+#endif
+
+/* Compensate the lack of matrix.c in pre-v4.20 kernels */
+int suse_msi_set_irq_unmanaged(struct device *dev)
+{
+#if IS_ENABLED(CONFIG_HYPERV)
+	struct msi_desc *msi_desc;
+	struct irq_desc *irq_desc;
+	struct cpumask *mask;
+	unsigned long flags;
+
+	if (x86_hyper_type != X86_HYPER_MS_HYPERV)
+		return 0;
+
+	for_each_msi_entry(msi_desc, dev) {
+		mask = kmalloc(sizeof(struct cpumask), GFP_KERNEL);
+		if (!mask)
+			return -ENOMEM;
+		cpumask_copy(mask, msi_desc->affinity);
+
+		/*
+		 * Set IRQ to unmanaged, and assign affinity_hint to be used by
+		 * irqbalance --hintpolicy=subset
+		 */
+		irq_desc = irq_get_desc_lock(msi_desc->irq, &flags,
+				IRQ_GET_DESC_CHECK_GLOBAL);
+		irqd_clear(&irq_desc->irq_data, IRQD_AFFINITY_MANAGED);
+		irq_desc->affinity_hint = mask;
+		irq_put_desc_unlock(irq_desc, flags);
+	}
+#endif
+	return 0;
+}
+EXPORT_SYMBOL_GPL(suse_msi_set_irq_unmanaged);
 
 /**
  * alloc_msi_entry - Allocate an initialize msi_entry