Introduce a new function pointer in the irq_chip structure(irq_set_auxdata)
which is responsible for updating data which is stored in a shared register
or data storage. For example, the idxd driver uses the auxiliary data API
to enable/set and disable PASID field that is in the IMS entry (introduced
in a later patch) and that data are not typically present in MSI entry.

Reviewed-by: Tony Luck <tony.l...@intel.com>
Signed-off-by: Megha Dey <megha....@intel.com>
---
 include/linux/interrupt.h |  2 ++
 include/linux/irq.h       |  4 ++++
 kernel/irq/manage.c       | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 38 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index bb8ff90..d3f419b 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -496,6 +496,8 @@ extern int irq_get_irqchip_state(unsigned int irq, enum 
irqchip_irq_state which,
 extern int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state 
which,
                                 bool state);
 
+int irq_set_auxdata(unsigned int irq, unsigned int which, u64 val);
+
 #ifdef CONFIG_IRQ_FORCED_THREADING
 # ifdef CONFIG_PREEMPT_RT
 #  define force_irqthreads     (true)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 4aeb1c4..568cdf5 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -491,6 +491,8 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data 
*d)
  *                             irq_request_resources
  * @irq_compose_msi_msg:       optional to compose message content for MSI
  * @irq_write_msi_msg: optional to write message content for MSI
+ * @irq_set_auxdata:   Optional function to update auxiliary data e.g. in
+ *                     shared registers
  * @irq_get_irqchip_state:     return the internal state of an interrupt
  * @irq_set_irqchip_state:     set the internal state of a interrupt
  * @irq_set_vcpu_affinity:     optional to target a vCPU in a virtual machine
@@ -538,6 +540,8 @@ struct irq_chip {
        void            (*irq_compose_msi_msg)(struct irq_data *data, struct 
msi_msg *msg);
        void            (*irq_write_msi_msg)(struct irq_data *data, struct 
msi_msg *msg);
 
+       int             (*irq_set_auxdata)(struct irq_data *data, unsigned int 
which, u64 auxval);
+
        int             (*irq_get_irqchip_state)(struct irq_data *data, enum 
irqchip_irq_state which, bool *state);
        int             (*irq_set_irqchip_state)(struct irq_data *data, enum 
irqchip_irq_state which, bool state);
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 85ede4e..68ff559 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2860,3 +2860,35 @@ bool irq_check_status_bit(unsigned int irq, unsigned int 
bitmask)
        return res;
 }
 EXPORT_SYMBOL_GPL(irq_check_status_bit);
+
+/**
+ * irq_set_auxdata - Set auxiliary data
+ * @irq:       Interrupt to update
+ * @which:     Selector which data to update
+ * @auxval:    Auxiliary data value
+ *
+ * Function to update auxiliary data for an interrupt, e.g. to update data
+ * which is stored in a shared register or data storage (e.g. IMS).
+ */
+int irq_set_auxdata(unsigned int irq, unsigned int which, u64 val)
+{
+       struct irq_desc *desc;
+       struct irq_data *data;
+       unsigned long flags;
+       int res = -ENODEV;
+
+       desc = irq_get_desc_buslock(irq, &flags, 0);
+       if (!desc)
+               return -EINVAL;
+
+       for (data = &desc->irq_data; data; data = irqd_get_parent_data(data)) {
+               if (data->chip->irq_set_auxdata) {
+                       res = data->chip->irq_set_auxdata(data, which, val);
+                       break;
+               }
+       }
+
+       irq_put_desc_busunlock(desc, flags);
+       return res;
+}
+EXPORT_SYMBOL_GPL(irq_set_auxdata);
-- 
2.7.4

Reply via email to