Skip to content

Commit 939fc85

Browse files
committed
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>
1 parent 08a491b commit 939fc85

5 files changed

Lines changed: 71 additions & 16 deletions

File tree

drivers/parisc/dino.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,8 @@ struct dino_device
142142
{
143143
struct pci_hba_data hba; /* 'C' inheritance - must be first */
144144
spinlock_t dinosaur_pen;
145-
unsigned long txn_addr; /* EIR addr to generate interrupt */
146-
u32 txn_data; /* EIR data assign to each dino */
147145
u32 imr; /* IRQ's which are enabled */
146+
struct gsc_irq gsc_irq;
148147
int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
149148
#ifdef DINO_DEBUG
150149
unsigned int dino_irr0; /* save most recent IRQ line stat */
@@ -339,14 +338,43 @@ static void dino_unmask_irq(struct irq_data *d)
339338
if (tmp & DINO_MASK_IRQ(local_irq)) {
340339
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
341340
__func__, tmp);
342-
gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
341+
gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr);
343342
}
344343
}
345344

345+
#ifdef CONFIG_SMP
346+
static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
347+
bool force)
348+
{
349+
struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
350+
struct cpumask tmask;
351+
int cpu_irq;
352+
u32 eim;
353+
354+
if (!cpumask_and(&tmask, dest, cpu_online_mask))
355+
return -EINVAL;
356+
357+
cpu_irq = cpu_check_affinity(d, &tmask);
358+
if (cpu_irq < 0)
359+
return cpu_irq;
360+
361+
dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
362+
eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
363+
__raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
364+
365+
irq_data_update_effective_affinity(d, &tmask);
366+
367+
return IRQ_SET_MASK_OK;
368+
}
369+
#endif
370+
346371
static struct irq_chip dino_interrupt_type = {
347372
.name = "GSC-PCI",
348373
.irq_unmask = dino_unmask_irq,
349374
.irq_mask = dino_mask_irq,
375+
#ifdef CONFIG_SMP
376+
.irq_set_affinity = dino_set_affinity_irq,
377+
#endif
350378
};
351379

352380

@@ -806,7 +834,6 @@ static int __init dino_common_init(struct parisc_device *dev,
806834
{
807835
int status;
808836
u32 eim;
809-
struct gsc_irq gsc_irq;
810837
struct resource *res;
811838

812839
pcibios_register_hba(&dino_dev->hba);
@@ -821,10 +848,8 @@ static int __init dino_common_init(struct parisc_device *dev,
821848
** still only has 11 IRQ input lines - just map some of them
822849
** to a different processor.
823850
*/
824-
dev->irq = gsc_alloc_irq(&gsc_irq);
825-
dino_dev->txn_addr = gsc_irq.txn_addr;
826-
dino_dev->txn_data = gsc_irq.txn_data;
827-
eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
851+
dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq);
852+
eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
828853

829854
/*
830855
** Dino needs a PA "IRQ" to get a processor's attention.

drivers/parisc/gsc.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,41 @@ static void gsc_asic_unmask_irq(struct irq_data *d)
135135
*/
136136
}
137137

138+
#ifdef CONFIG_SMP
139+
static int gsc_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
140+
bool force)
141+
{
142+
struct gsc_asic *gsc_dev = irq_data_get_irq_chip_data(d);
143+
struct cpumask tmask;
144+
int cpu_irq;
145+
146+
if (!cpumask_and(&tmask, dest, cpu_online_mask))
147+
return -EINVAL;
148+
149+
cpu_irq = cpu_check_affinity(d, &tmask);
150+
if (cpu_irq < 0)
151+
return cpu_irq;
152+
153+
gsc_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
154+
gsc_dev->eim = ((u32) gsc_dev->gsc_irq.txn_addr) | gsc_dev->gsc_irq.txn_data;
155+
156+
/* switch IRQ's for devices below LASI/WAX to other CPU */
157+
gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR);
158+
159+
irq_data_update_effective_affinity(d, &tmask);
160+
161+
return IRQ_SET_MASK_OK;
162+
}
163+
#endif
164+
165+
138166
static struct irq_chip gsc_asic_interrupt_type = {
139167
.name = "GSC-ASIC",
140168
.irq_unmask = gsc_asic_unmask_irq,
141169
.irq_mask = gsc_asic_mask_irq,
170+
#ifdef CONFIG_SMP
171+
.irq_set_affinity = gsc_set_affinity_irq,
172+
#endif
142173
};
143174

144175
int gsc_assign_irq(struct irq_chip *type, void *data)

drivers/parisc/gsc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct gsc_asic {
3131
int version;
3232
int type;
3333
int eim;
34+
struct gsc_irq gsc_irq;
3435
int global_irq[32];
3536
};
3637

drivers/parisc/lasi.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ static int __init lasi_init_chip(struct parisc_device *dev)
163163
{
164164
extern void (*chassis_power_off)(void);
165165
struct gsc_asic *lasi;
166-
struct gsc_irq gsc_irq;
167166
int ret;
168167

169168
lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
@@ -185,17 +184,17 @@ static int __init lasi_init_chip(struct parisc_device *dev)
185184
lasi_init_irq(lasi);
186185

187186
/* the IRQ lasi should use */
188-
dev->irq = gsc_alloc_irq(&gsc_irq);
187+
dev->irq = gsc_alloc_irq(&lasi->gsc_irq);
189188
if (dev->irq < 0) {
190189
printk(KERN_ERR "%s(): cannot get GSC irq\n",
191190
__func__);
192191
kfree(lasi);
193192
return -EBUSY;
194193
}
195194

196-
lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
195+
lasi->eim = ((u32) lasi->gsc_irq.txn_addr) | lasi->gsc_irq.txn_data;
197196

198-
ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
197+
ret = request_irq(lasi->gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
199198
if (ret < 0) {
200199
kfree(lasi);
201200
return ret;

drivers/parisc/wax.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ static int __init wax_init_chip(struct parisc_device *dev)
6868
{
6969
struct gsc_asic *wax;
7070
struct parisc_device *parent;
71-
struct gsc_irq gsc_irq;
7271
int ret;
7372

7473
wax = kzalloc(sizeof(*wax), GFP_KERNEL);
@@ -85,17 +84,17 @@ static int __init wax_init_chip(struct parisc_device *dev)
8584
wax_init_irq(wax);
8685

8786
/* the IRQ wax should use */
88-
dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
87+
dev->irq = gsc_claim_irq(&wax->gsc_irq, WAX_GSC_IRQ);
8988
if (dev->irq < 0) {
9089
printk(KERN_ERR "%s(): cannot get GSC irq\n",
9190
__func__);
9291
kfree(wax);
9392
return -EBUSY;
9493
}
9594

96-
wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
95+
wax->eim = ((u32) wax->gsc_irq.txn_addr) | wax->gsc_irq.txn_data;
9796

98-
ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
97+
ret = request_irq(wax->gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
9998
if (ret < 0) {
10099
kfree(wax);
101100
return ret;

0 commit comments

Comments
 (0)