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:
parent
c74e2f6ecc
commit
f7c3522030
@ -142,9 +142,8 @@ struct dino_device
|
|||||||
{
|
{
|
||||||
struct pci_hba_data hba; /* 'C' inheritance - must be first */
|
struct pci_hba_data hba; /* 'C' inheritance - must be first */
|
||||||
spinlock_t dinosaur_pen;
|
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 */
|
u32 imr; /* IRQ's which are enabled */
|
||||||
|
struct gsc_irq gsc_irq;
|
||||||
int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
|
int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
|
||||||
#ifdef DINO_DEBUG
|
#ifdef DINO_DEBUG
|
||||||
unsigned int dino_irr0; /* save most recent IRQ line stat */
|
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)) {
|
if (tmp & DINO_MASK_IRQ(local_irq)) {
|
||||||
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
|
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
|
||||||
__func__, tmp);
|
__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 = {
|
static struct irq_chip dino_interrupt_type = {
|
||||||
.name = "GSC-PCI",
|
.name = "GSC-PCI",
|
||||||
.irq_unmask = dino_unmask_irq,
|
.irq_unmask = dino_unmask_irq,
|
||||||
.irq_mask = dino_mask_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;
|
int status;
|
||||||
u32 eim;
|
u32 eim;
|
||||||
struct gsc_irq gsc_irq;
|
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
|
||||||
pcibios_register_hba(&dino_dev->hba);
|
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
|
** still only has 11 IRQ input lines - just map some of them
|
||||||
** to a different processor.
|
** to a different processor.
|
||||||
*/
|
*/
|
||||||
dev->irq = gsc_alloc_irq(&gsc_irq);
|
dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq);
|
||||||
dino_dev->txn_addr = gsc_irq.txn_addr;
|
eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
|
||||||
dino_dev->txn_data = gsc_irq.txn_data;
|
|
||||||
eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Dino needs a PA "IRQ" to get a processor's attention.
|
** 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 = {
|
static struct irq_chip gsc_asic_interrupt_type = {
|
||||||
.name = "GSC-ASIC",
|
.name = "GSC-ASIC",
|
||||||
.irq_unmask = gsc_asic_unmask_irq,
|
.irq_unmask = gsc_asic_unmask_irq,
|
||||||
.irq_mask = gsc_asic_mask_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)
|
int gsc_assign_irq(struct irq_chip *type, void *data)
|
||||||
|
@ -31,6 +31,7 @@ struct gsc_asic {
|
|||||||
int version;
|
int version;
|
||||||
int type;
|
int type;
|
||||||
int eim;
|
int eim;
|
||||||
|
struct gsc_irq gsc_irq;
|
||||||
int global_irq[32];
|
int global_irq[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,7 +163,6 @@ static int __init lasi_init_chip(struct parisc_device *dev)
|
|||||||
{
|
{
|
||||||
extern void (*chassis_power_off)(void);
|
extern void (*chassis_power_off)(void);
|
||||||
struct gsc_asic *lasi;
|
struct gsc_asic *lasi;
|
||||||
struct gsc_irq gsc_irq;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
|
lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
|
||||||
@ -185,7 +184,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
|
|||||||
lasi_init_irq(lasi);
|
lasi_init_irq(lasi);
|
||||||
|
|
||||||
/* the IRQ lasi should use */
|
/* the IRQ lasi should use */
|
||||||
dev->irq = gsc_alloc_irq(&gsc_irq);
|
dev->irq = gsc_alloc_irq(&lasi->gsc_irq);
|
||||||
if (dev->irq < 0) {
|
if (dev->irq < 0) {
|
||||||
printk(KERN_ERR "%s(): cannot get GSC irq\n",
|
printk(KERN_ERR "%s(): cannot get GSC irq\n",
|
||||||
__func__);
|
__func__);
|
||||||
@ -193,9 +192,9 @@ static int __init lasi_init_chip(struct parisc_device *dev)
|
|||||||
return -EBUSY;
|
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) {
|
if (ret < 0) {
|
||||||
kfree(lasi);
|
kfree(lasi);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -68,7 +68,6 @@ static int __init wax_init_chip(struct parisc_device *dev)
|
|||||||
{
|
{
|
||||||
struct gsc_asic *wax;
|
struct gsc_asic *wax;
|
||||||
struct parisc_device *parent;
|
struct parisc_device *parent;
|
||||||
struct gsc_irq gsc_irq;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wax = kzalloc(sizeof(*wax), GFP_KERNEL);
|
wax = kzalloc(sizeof(*wax), GFP_KERNEL);
|
||||||
@ -85,7 +84,7 @@ static int __init wax_init_chip(struct parisc_device *dev)
|
|||||||
wax_init_irq(wax);
|
wax_init_irq(wax);
|
||||||
|
|
||||||
/* the IRQ wax should use */
|
/* 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) {
|
if (dev->irq < 0) {
|
||||||
printk(KERN_ERR "%s(): cannot get GSC irq\n",
|
printk(KERN_ERR "%s(): cannot get GSC irq\n",
|
||||||
__func__);
|
__func__);
|
||||||
@ -93,9 +92,9 @@ static int __init wax_init_chip(struct parisc_device *dev)
|
|||||||
return -EBUSY;
|
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) {
|
if (ret < 0) {
|
||||||
kfree(wax);
|
kfree(wax);
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user