irqchip/loongson-htvec: Support 8 groups of HT vectors
authorHuacai Chen <chenhc@lemote.com>
Thu, 30 Jul 2020 08:51:29 +0000 (16:51 +0800)
committerMarc Zyngier <maz@kernel.org>
Thu, 30 Jul 2020 11:58:10 +0000 (12:58 +0100)
The original version can only used by old Loongson-3 which only use 4
groups of HT vectors. Now Loongson-3A R4 can use 8 groups, so improve
the driver to support all 8 groups.

Fixes: 818e915fbac518e8c78e1877a ("irqchip: Add Loongson HyperTransport Vector support")
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Link: https://lore.kernel.org/r/1596099090-23516-5-git-send-email-chenhc@lemote.com
drivers/irqchip/irq-loongson-htvec.c

index 720cf96ae90ee2fabd1ae198553aa0697212babd..13e6016fe46460ff09464ee1b276a86cceae564a 100644 (file)
 
 /* Registers */
 #define HTVEC_EN_OFF           0x20
-#define HTVEC_MAX_PARENT_IRQ   4
+#define HTVEC_MAX_PARENT_IRQ   8
 
 #define VEC_COUNT_PER_REG      32
-#define VEC_REG_COUNT          4
-#define VEC_COUNT              (VEC_COUNT_PER_REG * VEC_REG_COUNT)
 #define VEC_REG_IDX(irq_id)    ((irq_id) / VEC_COUNT_PER_REG)
 #define VEC_REG_BIT(irq_id)    ((irq_id) % VEC_COUNT_PER_REG)
 
 struct htvec {
+       int                     num_parents;
        void __iomem            *base;
        struct irq_domain       *htvec_domain;
        raw_spinlock_t          htvec_lock;
@@ -43,7 +42,7 @@ static void htvec_irq_dispatch(struct irq_desc *desc)
 
        chained_irq_enter(chip, desc);
 
-       for (i = 0; i < VEC_REG_COUNT; i++) {
+       for (i = 0; i < priv->num_parents; i++) {
                pending = readl(priv->base + 4 * i);
                while (pending) {
                        int bit = __ffs(pending);
@@ -150,7 +149,7 @@ static void htvec_reset(struct htvec *priv)
        u32 idx;
 
        /* Clear IRQ cause registers, mask all interrupts */
-       for (idx = 0; idx < VEC_REG_COUNT; idx++) {
+       for (idx = 0; idx < priv->num_parents; idx++) {
                writel_relaxed(0x0, priv->base + HTVEC_EN_OFF + 4 * idx);
                writel_relaxed(0xFFFFFFFF, priv->base);
        }
@@ -160,7 +159,7 @@ static int htvec_of_init(struct device_node *node,
                                struct device_node *parent)
 {
        struct htvec *priv;
-       int err, parent_irq[4], num_parents = 0, i;
+       int err, parent_irq[8], i;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -179,19 +178,18 @@ static int htvec_of_init(struct device_node *node,
                if (parent_irq[i] <= 0)
                        break;
 
-               num_parents++;
+               priv->num_parents++;
        }
 
-       if (!num_parents) {
+       if (!priv->num_parents) {
                pr_err("Failed to get parent irqs\n");
                err = -ENODEV;
                goto iounmap_base;
        }
 
        priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node),
-                                                     VEC_COUNT,
-                                                     &htvec_domain_ops,
-                                                     priv);
+                                       (VEC_COUNT_PER_REG * priv->num_parents),
+                                       &htvec_domain_ops, priv);
        if (!priv->htvec_domain) {
                pr_err("Failed to create IRQ domain\n");
                err = -ENOMEM;
@@ -200,7 +198,7 @@ static int htvec_of_init(struct device_node *node,
 
        htvec_reset(priv);
 
-       for (i = 0; i < num_parents; i++)
+       for (i = 0; i < priv->num_parents; i++)
                irq_set_chained_handler_and_data(parent_irq[i],
                                                 htvec_irq_dispatch, priv);