mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +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 */
|
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