#include <linux/mm.h>
#include <linux/notifier.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/efi.h>
#include <linux/percpu.h>
#include <asm/machvec.h>
#include <asm/mca.h>
#include <asm/page.h>
+#include <asm/paravirt.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/tlbflush.h>
#include <asm/unistd.h>
+#include <asm/sn/arch.h>
#define SMP_DEBUG 0
#define DEBUG_ITC_SYNC 0
-extern void __devinit calibrate_delay (void);
extern void start_ap (void);
extern unsigned long ia64_iobase;
-task_t *task_for_booting_cpu;
+struct task_struct *task_for_booting_cpu;
/*
* State for each CPU
EXPORT_SYMBOL(cpu_possible_map);
cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
+DEFINE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
+EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
+
int smp_num_siblings = 1;
-int smp_num_cpucores = 1;
/* which logical CPU number maps to which CPU (physical APIC ID) */
volatile int ia64_cpu_to_sapicid[NR_CPUS];
go[MASTER] = 1;
- if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) {
+ if (smp_call_function_single(master, sync_master, NULL, 0) < 0) {
printk(KERN_ERR "sync_itc: failed to get attention of CPU %u!\n", master);
return;
}
{
}
-static void __devinit
+static void __cpuinit
smp_callin (void)
{
int cpuid, phys_id, itc_master;
+ struct cpuinfo_ia64 *last_cpuinfo, *this_cpuinfo;
extern void ia64_init_itm(void);
extern volatile int time_keeper_id;
fix_b0_for_bsp();
- lock_ipi_calllock();
+ ipi_call_lock_irq();
+ spin_lock(&vector_lock);
+ /* Setup the per cpu irq handling data structures */
+ __setup_vector_irq(cpuid);
cpu_set(cpuid, cpu_online_map);
- unlock_ipi_calllock();
per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+ spin_unlock(&vector_lock);
+ ipi_call_unlock_irq();
smp_setup_percpu_timer();
* Get our bogomips.
*/
ia64_init_itm();
- calibrate_delay();
+
+ /*
+ * Delay calibration can be skipped if new processor is identical to the
+ * previous processor.
+ */
+ last_cpuinfo = cpu_data(cpuid - 1);
+ this_cpuinfo = local_cpu_data;
+ if (last_cpuinfo->itc_freq != this_cpuinfo->itc_freq ||
+ last_cpuinfo->proc_freq != this_cpuinfo->proc_freq ||
+ last_cpuinfo->features != this_cpuinfo->features ||
+ last_cpuinfo->revision != this_cpuinfo->revision ||
+ last_cpuinfo->family != this_cpuinfo->family ||
+ last_cpuinfo->archrev != this_cpuinfo->archrev ||
+ last_cpuinfo->model != this_cpuinfo->model)
+ calibrate_delay();
local_cpu_data->loops_per_jiffy = loops_per_jiffy;
#ifdef CONFIG_IA32_SUPPORT
/*
* Activate a secondary processor. head.S calls this.
*/
-int __devinit
+int __cpuinit
start_secondary (void *unused)
{
/* Early console may use I/O ports */
ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
+#ifndef CONFIG_PRINTK_TIME
Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
+#endif
efi_map_pal_code();
cpu_init();
preempt_disable();
return 0;
}
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
{
return NULL;
}
struct create_idle {
+ struct work_struct work;
struct task_struct *idle;
struct completion done;
int cpu;
};
-void
-do_fork_idle(void *_c_idle)
+void __cpuinit
+do_fork_idle(struct work_struct *work)
{
- struct create_idle *c_idle = _c_idle;
+ struct create_idle *c_idle =
+ container_of(work, struct create_idle, work);
c_idle->idle = fork_idle(c_idle->cpu);
complete(&c_idle->done);
}
-static int __devinit
+static int __cpuinit
do_boot_cpu (int sapicid, int cpu)
{
int timeout;
struct create_idle c_idle = {
+ .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
.cpu = cpu,
.done = COMPLETION_INITIALIZER(c_idle.done),
};
- DECLARE_WORK(work, do_fork_idle, &c_idle);
c_idle.idle = get_idle_for_cpu(cpu);
if (c_idle.idle) {
* We can't use kernel_thread since we must avoid to reschedule the child.
*/
if (!keventd_up() || current_is_keventd())
- work.func(work.data);
+ c_idle.work.func(&c_idle.work);
else {
- schedule_work(&work);
+ schedule_work(&c_idle.work);
wait_for_completion(&c_idle.done);
}
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callin_map);
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+ paravirt_post_smp_prepare_boot_cpu();
}
#ifdef CONFIG_HOTPLUG_CPU
{
int i;
- for_each_cpu_mask(i, cpu_sibling_map[cpu])
- cpu_clear(cpu, cpu_sibling_map[i]);
+ for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu))
+ cpu_clear(cpu, per_cpu(cpu_sibling_map, i));
for_each_cpu_mask(i, cpu_core_map[cpu])
cpu_clear(cpu, cpu_core_map[i]);
- cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
+ per_cpu(cpu_sibling_map, cpu) = cpu_core_map[cpu] = CPU_MASK_NONE;
}
static void
if (cpu_data(cpu)->threads_per_core == 1 &&
cpu_data(cpu)->cores_per_socket == 1) {
cpu_clear(cpu, cpu_core_map[cpu]);
- cpu_clear(cpu, cpu_sibling_map[cpu]);
+ cpu_clear(cpu, per_cpu(cpu_sibling_map, cpu));
return;
}
set_cpei_target_cpu(new_cpei_cpu);
desc = irq_desc + ia64_cpe_irq;
/*
- * Switch for now, immediatly, we need to do fake intr
+ * Switch for now, immediately, we need to do fake intr
* as other interrupts, but need to study CPEI behaviour with
* polling before making changes.
*/
return (-EBUSY);
}
+ if (ia64_platform_is("sn2")) {
+ if (!sn_cpu_disable_allowed(cpu))
+ return -EBUSY;
+ }
+
cpu_clear(cpu, cpu_online_map);
if (migrate_platform_irqs(cpu)) {
}
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
-#else /* !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
-{
- return -ENOSYS;
-}
-
-void __cpu_die(unsigned int cpu)
-{
- /* We said "no" in __cpu_disable */
- BUG();
-}
#endif /* CONFIG_HOTPLUG_CPU */
void
cpu_set(i, cpu_core_map[cpu]);
cpu_set(cpu, cpu_core_map[i]);
if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
- cpu_set(i, cpu_sibling_map[cpu]);
- cpu_set(cpu, cpu_sibling_map[i]);
+ cpu_set(i, per_cpu(cpu_sibling_map, cpu));
+ cpu_set(cpu, per_cpu(cpu_sibling_map, i));
}
}
}
}
-int __devinit
+int __cpuinit
__cpu_up (unsigned int cpu)
{
int ret;
if (cpu_data(cpu)->threads_per_core == 1 &&
cpu_data(cpu)->cores_per_socket == 1) {
- cpu_set(cpu, cpu_sibling_map[cpu]);
+ cpu_set(cpu, per_cpu(cpu_sibling_map, cpu));
cpu_set(cpu, cpu_core_map[cpu]);
return 0;
}
}
/*
- * Assume that CPU's have been discovered by some platform-dependent interface. For
+ * Assume that CPUs have been discovered by some platform-dependent interface. For
* SoftSDV/Lion, that would be ACPI.
*
* Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP().
} *ap_startup;
long sal_ret;
- /* Tell SAL where to drop the AP's. */
+ /* Tell SAL where to drop the APs. */
ap_startup = (struct fptr *) start_ap;
sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0);
u16 pltid;
pal_logical_to_physical_t info;
- if (smp_num_cpucores == 1 && smp_num_siblings == 1)
- return;
+ status = ia64_pal_logical_to_phys(-1, &info);
+ if (status != PAL_STATUS_SUCCESS) {
+ if (status != PAL_STATUS_UNIMPLEMENTED) {
+ printk(KERN_ERR
+ "ia64_pal_logical_to_phys failed with %ld\n",
+ status);
+ return;
+ }
- if ((status = ia64_pal_logical_to_phys(-1, &info)) != PAL_STATUS_SUCCESS) {
- printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
- status);
- return;
+ info.overview_ppid = 0;
+ info.overview_cpp = 1;
+ info.overview_tpc = 1;
}
- if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
- printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
+
+ status = ia64_sal_physical_id_info(&pltid);
+ if (status != PAL_STATUS_SUCCESS) {
+ if (status != PAL_STATUS_UNIMPLEMENTED)
+ printk(KERN_ERR
+ "ia64_sal_pltid failed with %ld\n",
+ status);
return;
}
c->socket_id = (pltid << 8) | info.overview_ppid;
+
+ if (info.overview_cpp == 1 && info.overview_tpc == 1)
+ return;
+
c->cores_per_socket = info.overview_cpp;
c->threads_per_core = info.overview_tpc;
c->num_log = info.overview_num_log;
c->core_id = info.log1_cid;
c->thread_id = info.log1_tid;
}
+
+/*
+ * returns non zero, if multi-threading is enabled
+ * on at least one physical package. Due to hotplug cpu
+ * and (maxcpus=), all threads may not necessarily be enabled
+ * even though the processor supports multi-threading.
+ */
+int is_multithreading_enabled(void)
+{
+ int i, j;
+
+ for_each_present_cpu(i) {
+ for_each_present_cpu(j) {
+ if (j == i)
+ continue;
+ if ((cpu_data(j)->socket_id == cpu_data(i)->socket_id)) {
+ if (cpu_data(j)->core_id == cpu_data(i)->core_id)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(is_multithreading_enabled);