parisc: Fix CPU affinity for Lasi, WAX and Dino chips

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>
This commit is contained in:
Helge Deller 2022-03-27 15:46:26 +02:00
parent 08a491b2e4
commit 939fc85667
5 changed files with 71 additions and 16 deletions

View 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.

View 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)

View File

@ -31,6 +31,7 @@ struct gsc_asic {
int version;
int type;
int eim;
struct gsc_irq gsc_irq;
int global_irq[32];
};

View 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;

View 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;