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

Commit 49b424fe authored by Max Filippov's avatar Max Filippov Committed by Chris Zankel
Browse files

xtensa: implement CPU hotplug



Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarChris Zankel <chris@zankel.net>
parent f615136c
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -140,6 +140,15 @@ config NR_CPUS
	range 2 32
	range 2 32
	default "4"
	default "4"


config HOTPLUG_CPU
	bool "Enable CPU hotplug support"
	depends on SMP
	help
	  Say Y here to allow turning CPUs off and on. CPUs can be
	  controlled through /sys/devices/system/cpu.

	  Say N if you want to disable CPU hotplug.

config MATH_EMULATION
config MATH_EMULATION
	bool "Math emulation"
	bool "Math emulation"
	help
	help
+1 −0
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ static __inline__ int irq_canonicalize(int irq)
struct irqaction;
struct irqaction;
struct irq_domain;
struct irq_domain;


void migrate_irqs(void);
int xtensa_irq_domain_xlate(const u32 *intspec, unsigned int intsize,
int xtensa_irq_domain_xlate(const u32 *intspec, unsigned int intsize,
		unsigned long int_irq, unsigned long ext_irq,
		unsigned long int_irq, unsigned long ext_irq,
		unsigned long *out_hwirq, unsigned int *out_type);
		unsigned long *out_hwirq, unsigned int *out_type);
+9 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,15 @@ void ipi_init(void);
struct seq_file;
struct seq_file;
void show_ipi_list(struct seq_file *p, int prec);
void show_ipi_list(struct seq_file *p, int prec);


#ifdef CONFIG_HOTPLUG_CPU

void __cpu_die(unsigned int cpu);
int __cpu_disable(void);
void cpu_die(void);
void cpu_restart(void);

#endif /* CONFIG_HOTPLUG_CPU */

#endif /* CONFIG_SMP */
#endif /* CONFIG_SMP */


#endif	/* _XTENSA_SMP_H */
#endif	/* _XTENSA_SMP_H */
+50 −1
Original line number Original line Diff line number Diff line
@@ -103,7 +103,7 @@ _SetupMMU:


ENDPROC(_start)
ENDPROC(_start)


	__INIT
	__REF
	.literal_position
	.literal_position


ENTRY(_startup)
ENTRY(_startup)
@@ -302,6 +302,55 @@ should_never_return:


ENDPROC(_startup)
ENDPROC(_startup)


#ifdef CONFIG_HOTPLUG_CPU

ENTRY(cpu_restart)

#if XCHAL_DCACHE_IS_WRITEBACK
	___flush_invalidate_dcache_all a2 a3
#else
	___invalidate_dcache_all a2 a3
#endif
	memw
	movi	a2, CCON	# MX External Register to Configure Cache
	movi	a3, 0
	wer	a3, a2
	extw

	rsr	a0, prid
	neg	a2, a0
	movi	a3, cpu_start_id
	s32i	a2, a3, 0
#if XCHAL_DCACHE_IS_WRITEBACK
	dhwbi	a3, 0
#endif
1:
	l32i	a2, a3, 0
	dhi	a3, 0
	bne	a2, a0, 1b

	/*
	 * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
	 * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
	 * xt-gdb to single step via DEBUG exceptions received directly
	 * by ocd.
	 */
	movi	a1, 1
	movi	a0, 0
	wsr	a1, windowstart
	wsr	a0, windowbase
	rsync

	movi	a1, LOCKLEVEL
	wsr	a1, ps
	rsync

	j	_startup

ENDPROC(cpu_restart)

#endif  /* CONFIG_HOTPLUG_CPU */

/*
/*
 * DATA section
 * DATA section
 */
 */
+49 −0
Original line number Original line Diff line number Diff line
@@ -153,3 +153,52 @@ void __init init_IRQ(void)
#endif
#endif
	variant_init_irq();
	variant_init_irq();
}
}

#ifdef CONFIG_HOTPLUG_CPU
static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
{
	struct irq_desc *desc = irq_to_desc(irq);
	struct irq_chip *chip = irq_data_get_irq_chip(data);
	unsigned long flags;

	raw_spin_lock_irqsave(&desc->lock, flags);
	if (chip->irq_set_affinity)
		chip->irq_set_affinity(data, cpumask_of(cpu), false);
	raw_spin_unlock_irqrestore(&desc->lock, flags);
}

/*
 * The CPU has been marked offline.  Migrate IRQs off this CPU.  If
 * the affinity settings do not allow other CPUs, force them onto any
 * available CPU.
 */
void migrate_irqs(void)
{
	unsigned int i, cpu = smp_processor_id();
	struct irq_desc *desc;

	for_each_irq_desc(i, desc) {
		struct irq_data *data = irq_desc_get_irq_data(desc);
		unsigned int newcpu;

		if (irqd_is_per_cpu(data))
			continue;

		if (!cpumask_test_cpu(cpu, data->affinity))
			continue;

		newcpu = cpumask_any_and(data->affinity, cpu_online_mask);

		if (newcpu >= nr_cpu_ids) {
			pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
					    i, cpu);

			cpumask_setall(data->affinity);
			newcpu = cpumask_any_and(data->affinity,
						 cpu_online_mask);
		}

		route_irq(data, i, newcpu);
	}
}
#endif /* CONFIG_HOTPLUG_CPU */
Loading