123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * ip30-smp.c: SMP on IP30 architecture.
- * Based off of the original IP30 SMP code, with inspiration from ip27-smp.c
- * and smp-bmips.c.
- *
- * Copyright (C) 2005-2007 Stanislaw Skowronek <[email protected]>
- * 2006-2007, 2014-2015 Joshua Kinard <[email protected]>
- * 2009 Johannes Dickgreber <[email protected]>
- */
- #include <linux/init.h>
- #include <linux/sched.h>
- #include <linux/sched/task_stack.h>
- #include <asm/time.h>
- #include <asm/sgi/heart.h>
- #include "ip30-common.h"
- #define MPCONF_MAGIC 0xbaddeed2
- #define MPCONF_ADDR 0xa800000000000600L
- #define MPCONF_SIZE 0x80
- #define MPCONF(x) (MPCONF_ADDR + (x) * MPCONF_SIZE)
- /* HEART can theoretically do 4 CPUs, but only 2 are physically possible */
- #define MP_NCPU 2
- struct mpconf {
- u32 magic;
- u32 prid;
- u32 physid;
- u32 virtid;
- u32 scachesz;
- u16 fanloads;
- u16 res;
- void *launch;
- void *rendezvous;
- u64 res2[3];
- void *stackaddr;
- void *lnch_parm;
- void *rndv_parm;
- u32 idleflag;
- };
- static void ip30_smp_send_ipi_single(int cpu, u32 action)
- {
- int irq;
- switch (action) {
- case SMP_RESCHEDULE_YOURSELF:
- irq = HEART_L2_INT_RESCHED_CPU_0;
- break;
- case SMP_CALL_FUNCTION:
- irq = HEART_L2_INT_CALL_CPU_0;
- break;
- default:
- panic("IP30: Unknown action value in %s!\n", __func__);
- }
- irq += cpu;
- /* Poke the other CPU -- it's got mail! */
- heart_write(BIT_ULL(irq), &heart_regs->set_isr);
- }
- static void ip30_smp_send_ipi_mask(const struct cpumask *mask, u32 action)
- {
- u32 i;
- for_each_cpu(i, mask)
- ip30_smp_send_ipi_single(i, action);
- }
- static void __init ip30_smp_setup(void)
- {
- int i;
- int ncpu = 0;
- struct mpconf *mpc;
- init_cpu_possible(cpumask_of(0));
- /* Scan the MPCONF structure and enumerate available CPUs. */
- for (i = 0; i < MP_NCPU; i++) {
- mpc = (struct mpconf *)MPCONF(i);
- if (mpc->magic == MPCONF_MAGIC) {
- set_cpu_possible(i, true);
- __cpu_number_map[i] = ++ncpu;
- __cpu_logical_map[ncpu] = i;
- pr_info("IP30: Slot: %d, PrID: %.8x, PhyID: %d, VirtID: %d\n",
- i, mpc->prid, mpc->physid, mpc->virtid);
- }
- }
- pr_info("IP30: Detected %d CPU(s) present.\n", ncpu);
- /*
- * Set the coherency algorithm to '5' (cacheable coherent
- * exclusive on write). This is needed on IP30 SMP, especially
- * for R14000 CPUs, otherwise, instruction bus errors will
- * occur upon reaching userland.
- */
- change_c0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW);
- }
- static void __init ip30_smp_prepare_cpus(unsigned int max_cpus)
- {
- /* nothing to do here */
- }
- static int __init ip30_smp_boot_secondary(int cpu, struct task_struct *idle)
- {
- struct mpconf *mpc = (struct mpconf *)MPCONF(cpu);
- /* Stack pointer (sp). */
- mpc->stackaddr = (void *)__KSTK_TOS(idle);
- /* Global pointer (gp). */
- mpc->lnch_parm = task_thread_info(idle);
- mb(); /* make sure stack and lparm are written */
- /* Boot CPUx. */
- mpc->launch = smp_bootstrap;
- /* CPUx now executes smp_bootstrap, then ip30_smp_finish */
- return 0;
- }
- static void __init ip30_smp_init_cpu(void)
- {
- ip30_per_cpu_init();
- }
- static void __init ip30_smp_finish(void)
- {
- enable_percpu_irq(get_c0_compare_int(), IRQ_TYPE_NONE);
- local_irq_enable();
- }
- struct plat_smp_ops __read_mostly ip30_smp_ops = {
- .send_ipi_single = ip30_smp_send_ipi_single,
- .send_ipi_mask = ip30_smp_send_ipi_mask,
- .smp_setup = ip30_smp_setup,
- .prepare_cpus = ip30_smp_prepare_cpus,
- .boot_secondary = ip30_smp_boot_secondary,
- .init_secondary = ip30_smp_init_cpu,
- .smp_finish = ip30_smp_finish,
- .prepare_boot_cpu = ip30_smp_init_cpu,
- };
|