mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
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:
parent
08a491b2e4
commit
939fc85667
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user