Generic IMS irq chips and irq domain implementations for IMS based devices
in both variants:
- Message store in an array in device memory
- Message store in system RAM (part of queue memory)
Allocation and freeing of interrupts happens via the generic
msi_domain_alloc/free_irqs() interface. No special purpose IMS magic
required as long as the interrupt domain is stored in the underlying device
struct.
Completely untested of course and mostly for illustration and educational
purpose. This should of course be a modular irq chip, but adding that
support is left as an exercise for the people who care about this deeply.
Signed-off-by: Thomas Gleixner
---
V2: Reworked to handle both devmem arrays and queue based storage.
---
drivers/irqchip/Kconfig | 19 +
drivers/irqchip/Makefile|1
drivers/irqchip/irq-ims-msi.c | 343
include/linux/irqchip/irq-ims-msi.h | 95 +
4 files changed, 458 insertions(+)
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -571,4 +571,23 @@ config LOONGSON_PCH_MSI
help
Support for the Loongson PCH MSI Controller.
+config IMS_MSI
+ depends on PCI
+ select DEVICE_MSI
+ bool
+
+config IMS_MSI_ARRAY
+ bool "IMS Interrupt Message Storm MSI controller for device memory
storage arrays"
+ select IMS_MSI
+ help
+ Support for IMS Interrupt Message Storm MSI controller
+ with IMS slot storage in a slot array in device memory
+
+config IMS_MSI_QUEUE
+ bool "IMS Interrupt Message Storm MSI controller for IMS queue storage"
+ select IMS_MSI
+ help
+ Support for IMS Interrupt Message Storm MSI controller
+ with IMS slot storage in the queue storage of a device
+
endmenu
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -111,3 +111,4 @@ obj-$(CONFIG_LOONGSON_HTPIC)+= irq-loo
obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
obj-$(CONFIG_LOONGSON_PCH_PIC) += irq-loongson-pch-pic.o
obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o
+obj-$(CONFIG_IMS_MSI) += irq-ims-msi.o
--- /dev/null
+++ b/drivers/irqchip/irq-ims-msi.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+// (C) Copyright 2020 Thomas Gleixner
+/*
+ * Shared interrupt chips and irq domains for IMS devices
+ */
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef CONFIG_IMS_ARRAY
+
+struct ims_array_data {
+ struct ims_array_info info;
+ unsigned long map[0];
+};
+
+static void ims_array_mask_irq(struct irq_data *data)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+ struct ims_slot __iomem *slot = desc->device_msi.priv_iomem;
+ u32 __iomem *ctrl = &slot->ctrl;
+
+ iowrite32(ioread32(ctrl) & ~IMS_VECTOR_CTRL_UNMASK, ctrl);
+}
+
+static void ims_array_unmask_irq(struct irq_data *data)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+ struct ims_slot __iomem *slot = desc->device_msi.priv_iomem;
+ u32 __iomem *ctrl = &slot->ctrl;
+
+ iowrite32(ioread32(ctrl) | IMS_VECTOR_CTRL_UNMASK, ctrl);
+}
+
+static void ims_array_write_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+ struct ims_slot __iomem *slot = desc->device_msi.priv_iomem;
+
+ iowrite32(msg->address_lo, &slot->address_lo);
+ iowrite32(msg->address_hi, &slot->address_hi);
+ iowrite32(msg->data, &slot->data);
+}
+
+static const struct irq_chip ims_array_msi_controller = {
+ .name = "IMS",
+ .irq_mask = ims_array_mask_irq,
+ .irq_unmask = ims_array_unmask_irq,
+ .irq_write_msi_msg = ims_array_write_msi_msg,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void ims_array_reset_slot(struct ims_slot __iomem *slot)
+{
+ iowrite32(0, &slot->address_lo);
+ iowrite32(0, &slot->address_hi);
+ iowrite32(0, &slot->data);
+ iowrite32(0, &slot->ctrl);
+}
+
+static void ims_array_free_msi_store(struct irq_domain *domain,
+struct device *dev)
+{
+ struct msi_domain_info *info = domain->host_data;
+ struct ims_array_data *ims = info->data;
+ struct msi_desc *entry;
+
+ for_each_msi_entry(entry, dev) {
+ if (entry->device_msi.priv_iomem) {
+ clear_bit(entry->device_msi.hwirq, ims->map);
+ ims_array_reset_slot(entry->device_msi.priv_iomem);
+