parisc: Fix CPU affinity for Lasi, WAX and Dino chips
authorHelge Deller <deller@gmx.de>
Sun, 27 Mar 2022 13:46:26 +0000 (15:46 +0200)
committerHelge Deller <deller@gmx.de>
Tue, 29 Mar 2022 19:37:12 +0000 (21:37 +0200)
Add the missing logic to allow Lasi, WAX and Dino to set the
CPU affinity. This fixes IRQ migration to other CPUs when a
CPU is shutdown which currently holds the IRQs for one of those
chips.

Signed-off-by: Helge Deller <deller@gmx.de>
drivers/parisc/dino.c
drivers/parisc/gsc.c
drivers/parisc/gsc.h
drivers/parisc/lasi.c
drivers/parisc/wax.c

index 952a925..e330362 100644 (file)
@@ -142,9 +142,8 @@ struct dino_device
 {
        struct pci_hba_data     hba;    /* 'C' inheritance - must be first */
        spinlock_t              dinosaur_pen;
-       unsigned long           txn_addr; /* EIR addr to generate interrupt */ 
-       u32                     txn_data; /* EIR data assign to each dino */ 
        u32                     imr;      /* IRQ's which are enabled */ 
+       struct gsc_irq          gsc_irq;
        int                     global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
 #ifdef DINO_DEBUG
        unsigned int            dino_irr0; /* save most recent IRQ line stat */
@@ -339,14 +338,43 @@ static void dino_unmask_irq(struct irq_data *d)
        if (tmp & DINO_MASK_IRQ(local_irq)) {
                DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
                                __func__, tmp);
-               gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
+               gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr);
        }
 }
 
+#ifdef CONFIG_SMP
+static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+                               bool force)
+{
+       struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
+       struct cpumask tmask;
+       int cpu_irq;
+       u32 eim;
+
+       if (!cpumask_and(&tmask, dest, cpu_online_mask))
+               return -EINVAL;
+
+       cpu_irq = cpu_check_affinity(d, &tmask);
+       if (cpu_irq < 0)
+               return cpu_irq;
+
+       dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+       eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
+       __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
+
+       irq_data_update_effective_affinity(d, &tmask);
+
+       return IRQ_SET_MASK_OK;
+}
+#endif
+
 static struct irq_chip dino_interrupt_type = {
        .name           = "GSC-PCI",
        .irq_unmask     = dino_unmask_irq,
        .irq_mask       = dino_mask_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = dino_set_affinity_irq,
+#endif
 };
 
 
@@ -806,7 +834,6 @@ static int __init dino_common_init(struct parisc_device *dev,
 {
        int status;
        u32 eim;
-       struct gsc_irq gsc_irq;
        struct resource *res;
 
        pcibios_register_hba(&dino_dev->hba);
@@ -821,10 +848,8 @@ static int __init dino_common_init(struct parisc_device *dev,
        **   still only has 11 IRQ input lines - just map some of them
        **   to a different processor.
        */
-       dev->irq = gsc_alloc_irq(&gsc_irq);
-       dino_dev->txn_addr = gsc_irq.txn_addr;
-       dino_dev->txn_data = gsc_irq.txn_data;
-       eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq);
+       eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
 
        /* 
        ** Dino needs a PA "IRQ" to get a processor's attention.
index ed9371a..ec175ae 100644 (file)
@@ -135,10 +135,41 @@ static void gsc_asic_unmask_irq(struct irq_data *d)
         */
 }
 
+#ifdef CONFIG_SMP
+static int gsc_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+                               bool force)
+{
+       struct gsc_asic *gsc_dev = irq_data_get_irq_chip_data(d);
+       struct cpumask tmask;
+       int cpu_irq;
+
+       if (!cpumask_and(&tmask, dest, cpu_online_mask))
+               return -EINVAL;
+
+       cpu_irq = cpu_check_affinity(d, &tmask);
+       if (cpu_irq < 0)
+               return cpu_irq;
+
+       gsc_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+       gsc_dev->eim = ((u32) gsc_dev->gsc_irq.txn_addr) | gsc_dev->gsc_irq.txn_data;
+
+       /* switch IRQ's for devices below LASI/WAX to other CPU */
+       gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR);
+
+       irq_data_update_effective_affinity(d, &tmask);
+
+       return IRQ_SET_MASK_OK;
+}
+#endif
+
+
 static struct irq_chip gsc_asic_interrupt_type = {
        .name           =       "GSC-ASIC",
        .irq_unmask     =       gsc_asic_unmask_irq,
        .irq_mask       =       gsc_asic_mask_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity =     gsc_set_affinity_irq,
+#endif
 };
 
 int gsc_assign_irq(struct irq_chip *type, void *data)
index 86abad3..73cbd0b 100644 (file)
@@ -31,6 +31,7 @@ struct gsc_asic {
        int version;
        int type;
        int eim;
+       struct gsc_irq gsc_irq;
        int global_irq[32];
 };
 
index 4e4fd12..6ef621a 100644 (file)
@@ -163,7 +163,6 @@ static int __init lasi_init_chip(struct parisc_device *dev)
 {
        extern void (*chassis_power_off)(void);
        struct gsc_asic *lasi;
-       struct gsc_irq gsc_irq;
        int ret;
 
        lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
@@ -185,7 +184,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
        lasi_init_irq(lasi);
 
        /* the IRQ lasi should use */
-       dev->irq = gsc_alloc_irq(&gsc_irq);
+       dev->irq = gsc_alloc_irq(&lasi->gsc_irq);
        if (dev->irq < 0) {
                printk(KERN_ERR "%s(): cannot get GSC irq\n",
                                __func__);
@@ -193,9 +192,9 @@ static int __init lasi_init_chip(struct parisc_device *dev)
                return -EBUSY;
        }
 
-       lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       lasi->eim = ((u32) lasi->gsc_irq.txn_addr) | lasi->gsc_irq.txn_data;
 
-       ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
+       ret = request_irq(lasi->gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
        if (ret < 0) {
                kfree(lasi);
                return ret;
index 5b6df15..73a2b01 100644 (file)
@@ -68,7 +68,6 @@ static int __init wax_init_chip(struct parisc_device *dev)
 {
        struct gsc_asic *wax;
        struct parisc_device *parent;
-       struct gsc_irq gsc_irq;
        int ret;
 
        wax = kzalloc(sizeof(*wax), GFP_KERNEL);
@@ -85,7 +84,7 @@ static int __init wax_init_chip(struct parisc_device *dev)
        wax_init_irq(wax);
 
        /* the IRQ wax should use */
-       dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
+       dev->irq = gsc_claim_irq(&wax->gsc_irq, WAX_GSC_IRQ);
        if (dev->irq < 0) {
                printk(KERN_ERR "%s(): cannot get GSC irq\n",
                                __func__);
@@ -93,9 +92,9 @@ static int __init wax_init_chip(struct parisc_device *dev)
                return -EBUSY;
        }
 
-       wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       wax->eim = ((u32) wax->gsc_irq.txn_addr) | wax->gsc_irq.txn_data;
 
-       ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
+       ret = request_irq(wax->gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
        if (ret < 0) {
                kfree(wax);
                return ret;