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