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

[ Upstream commit 939fc856676c266c3bc347c1c1661872a3725c0f ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Helge Deller 2022-03-27 15:46:26 +02:00 committed by Greg Kroah-Hartman
parent 1b8a6d1bda
commit bab8e3b4f6
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;