Commit 939fc856 authored by Helge Deller's avatar Helge Deller
Browse files

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: default avatarHelge Deller <deller@gmx.de>
parent 08a491b2
Loading
Loading
Loading
Loading
+33 −8
Original line number Diff line number Diff line
@@ -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.
+31 −0
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct gsc_asic {
	int version;
	int type;
	int eim;
	struct gsc_irq gsc_irq;
	int global_irq[32];
};

+3 −4
Original line number Diff line number Diff line
@@ -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;
+3 −4
Original line number Diff line number Diff line
@@ -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;