Thomas Bogendoerfer da7016
From: Thomas Gleixner <tglx@linutronix.de>
Thomas Bogendoerfer da7016
Date: Fri, 3 Sep 2021 11:24:17 -0400
Thomas Bogendoerfer da7016
Subject: genirq: Provide new interfaces for affinity hints
Thomas Bogendoerfer da7016
Patch-mainline: v5.17-rc1
Thomas Bogendoerfer da7016
Git-commit: 65c7cdedeb3026fabcc967a7aae2f755ad4d0783
Thomas Bogendoerfer da7016
References: bsc#1208153
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
The discussion about removing the side effect of irq_set_affinity_hint() of
Thomas Bogendoerfer da7016
actually applying the cpumask (if not NULL) as affinity to the interrupt,
Thomas Bogendoerfer da7016
unearthed a few unpleasantries:
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
  1) The modular perf drivers rely on the current behaviour for the very
Thomas Bogendoerfer da7016
     wrong reasons.
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
  2) While none of the other drivers prevents user space from changing
Thomas Bogendoerfer da7016
     the affinity, a cursorily inspection shows that there are at least
Thomas Bogendoerfer da7016
     expectations in some drivers.
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
#1 needs to be cleaned up anyway, so that's not a problem
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
#2 might result in subtle regressions especially when irqbalanced (which
Thomas Bogendoerfer da7016
   nowadays ignores the affinity hint) is disabled.
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
Provide new interfaces:
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
  irq_update_affinity_hint()  - Only sets the affinity hint pointer
Thomas Bogendoerfer da7016
  irq_set_affinity_and_hint() - Set the pointer and apply the affinity to
Thomas Bogendoerfer da7016
                                the interrupt
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
Make irq_set_affinity_hint() a wrapper around irq_apply_affinity_hint() and
Thomas Bogendoerfer da7016
document it to be phased out.
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
SUSE: For kABI compliance changed this patch to leave irq_set_affinity_hint()
Thomas Bogendoerfer da7016
      alone and only add the new interfaces.
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Thomas Bogendoerfer da7016
Signed-off-by: Nitesh Narayan Lal <nitesh@redhat.com>
Thomas Bogendoerfer da7016
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Thomas Bogendoerfer da7016
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Thomas Bogendoerfer da7016
Link: https://lore.kernel.org/r/20210501021832.743094-1-jesse.brandeburg@intel.com
Thomas Bogendoerfer da7016
Link: https://lore.kernel.org/r/20210903152430.244937-2-nitesh@redhat.com
Thomas Bogendoerfer da7016
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Thomas Bogendoerfer da7016
---
Thomas Bogendoerfer da7016
 include/linux/interrupt.h |   42 ++++++++++++++++++++++++++++++++++++++++++
Thomas Bogendoerfer da7016
 kernel/irq/manage.c       |   16 ++++++++++++++++
Thomas Bogendoerfer da7016
 2 files changed, 58 insertions(+)
Thomas Bogendoerfer da7016
Thomas Bogendoerfer da7016
--- a/include/linux/interrupt.h
Thomas Bogendoerfer da7016
+++ b/include/linux/interrupt.h
Thomas Bogendoerfer da7016
@@ -336,6 +336,36 @@ extern int irq_can_set_affinity(unsigned
Thomas Bogendoerfer da7016
 extern int irq_select_affinity(unsigned int irq);
Thomas Bogendoerfer da7016
 
Thomas Bogendoerfer da7016
 extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
Thomas Bogendoerfer da7016
+extern int __irq_apply_affinity_hint(unsigned int irq, const struct cpumask *m,
Thomas Bogendoerfer da7016
+				     bool setaffinity);
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
+/**
Thomas Bogendoerfer da7016
+ * irq_update_affinity_hint - Update the affinity hint
Thomas Bogendoerfer da7016
+ * @irq:	Interrupt to update
Thomas Bogendoerfer da7016
+ * @m:		cpumask pointer (NULL to clear the hint)
Thomas Bogendoerfer da7016
+ *
Thomas Bogendoerfer da7016
+ * Updates the affinity hint, but does not change the affinity of the interrupt.
Thomas Bogendoerfer da7016
+ */
Thomas Bogendoerfer da7016
+static inline int
Thomas Bogendoerfer da7016
+irq_update_affinity_hint(unsigned int irq, const struct cpumask *m)
Thomas Bogendoerfer da7016
+{
Thomas Bogendoerfer da7016
+	return __irq_apply_affinity_hint(irq, m, false);
Thomas Bogendoerfer da7016
+}
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
+/**
Thomas Bogendoerfer da7016
+ * irq_set_affinity_and_hint - Update the affinity hint and apply the provided
Thomas Bogendoerfer da7016
+ *			     cpumask to the interrupt
Thomas Bogendoerfer da7016
+ * @irq:	Interrupt to update
Thomas Bogendoerfer da7016
+ * @m:		cpumask pointer (NULL to clear the hint)
Thomas Bogendoerfer da7016
+ *
Thomas Bogendoerfer da7016
+ * Updates the affinity hint and if @m is not NULL it applies it as the
Thomas Bogendoerfer da7016
+ * affinity of that interrupt.
Thomas Bogendoerfer da7016
+ */
Thomas Bogendoerfer da7016
+static inline int
Thomas Bogendoerfer da7016
+irq_set_affinity_and_hint(unsigned int irq, const struct cpumask *m)
Thomas Bogendoerfer da7016
+{
Thomas Bogendoerfer da7016
+	return __irq_apply_affinity_hint(irq, m, true);
Thomas Bogendoerfer da7016
+}
Thomas Bogendoerfer da7016
 
Thomas Bogendoerfer da7016
 extern int
Thomas Bogendoerfer da7016
 irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
Thomas Bogendoerfer da7016
@@ -365,6 +395,18 @@ static inline int irq_can_set_affinity(u
Thomas Bogendoerfer da7016
 
Thomas Bogendoerfer da7016
 static inline int irq_select_affinity(unsigned int irq)  { return 0; }
Thomas Bogendoerfer da7016
 
Thomas Bogendoerfer da7016
+static inline int irq_update_affinity_hint(unsigned int irq,
Thomas Bogendoerfer da7016
+					   const struct cpumask *m)
Thomas Bogendoerfer da7016
+{
Thomas Bogendoerfer da7016
+	return -EINVAL;
Thomas Bogendoerfer da7016
+}
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
+static inline int irq_set_affinity_and_hint(unsigned int irq,
Thomas Bogendoerfer da7016
+					    const struct cpumask *m)
Thomas Bogendoerfer da7016
+{
Thomas Bogendoerfer da7016
+	return -EINVAL;
Thomas Bogendoerfer da7016
+}
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
 static inline int irq_set_affinity_hint(unsigned int irq,
Thomas Bogendoerfer da7016
 					const struct cpumask *m)
Thomas Bogendoerfer da7016
 {
Thomas Bogendoerfer da7016
--- a/kernel/irq/manage.c
Thomas Bogendoerfer da7016
+++ b/kernel/irq/manage.c
Thomas Bogendoerfer da7016
@@ -322,6 +322,22 @@ int irq_set_affinity_hint(unsigned int i
Thomas Bogendoerfer da7016
 }
Thomas Bogendoerfer da7016
 EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
Thomas Bogendoerfer da7016
 
Thomas Bogendoerfer da7016
+int __irq_apply_affinity_hint(unsigned int irq, const struct cpumask *m,
Thomas Bogendoerfer da7016
+			      bool setaffinity)
Thomas Bogendoerfer da7016
+{
Thomas Bogendoerfer da7016
+	unsigned long flags;
Thomas Bogendoerfer da7016
+	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
+	if (!desc)
Thomas Bogendoerfer da7016
+		return -EINVAL;
Thomas Bogendoerfer da7016
+	desc->affinity_hint = m;
Thomas Bogendoerfer da7016
+	irq_put_desc_unlock(desc, flags);
Thomas Bogendoerfer da7016
+	if (m && setaffinity)
Thomas Bogendoerfer da7016
+		__irq_set_affinity(irq, m, false);
Thomas Bogendoerfer da7016
+	return 0;
Thomas Bogendoerfer da7016
+}
Thomas Bogendoerfer da7016
+EXPORT_SYMBOL_GPL(__irq_apply_affinity_hint);
Thomas Bogendoerfer da7016
+
Thomas Bogendoerfer da7016
 static void irq_affinity_notify(struct work_struct *work)
Thomas Bogendoerfer da7016
 {
Thomas Bogendoerfer da7016
 	struct irq_affinity_notify *notify =