parisc: Fix CPU affinity for Lasi, WAX and Dino chips
[ Upstream commit 939fc85667
]
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:
Родитель
30dd4af48a
Коммит
f77f482ec3
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -31,6 +31,7 @@ struct gsc_asic {
|
|||
int version;
|
||||
int type;
|
||||
int eim;
|
||||
struct gsc_irq gsc_irq;
|
||||
int global_irq[32];
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче