Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bab8e3b4 authored by Helge Deller's avatar Helge Deller Committed by Greg Kroah-Hartman
Browse files

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: default avatarHelge Deller <deller@gmx.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 1b8a6d1b
Loading
Loading
Loading
Loading
+33 −8
Original line number Original line Diff line number Diff line
@@ -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.
+31 −0
Original line number Original line 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 = {
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)
+1 −0
Original line number Original line Diff line number Diff line
@@ -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];
};
};


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