/*1* linux/arch/m32r/kernel/smp.c2*3* M32R SMP support routines.4*5* Copyright (c) 2001, 2002 Hitoshi Yamamoto6*7* Taken from i386 version.8* (c) 1995 Alan Cox, Building #3 <[email protected]>9* (c) 1998-99, 2000 Ingo Molnar <[email protected]>10*11* This code is released under the GNU General Public License version 2 or12* later.13*/1415#undef DEBUG_SMP1617#include <linux/irq.h>18#include <linux/interrupt.h>19#include <linux/sched.h>20#include <linux/spinlock.h>21#include <linux/mm.h>22#include <linux/smp.h>23#include <linux/profile.h>24#include <linux/cpu.h>2526#include <asm/cacheflush.h>27#include <asm/pgalloc.h>28#include <asm/atomic.h>29#include <asm/io.h>30#include <asm/mmu_context.h>31#include <asm/m32r.h>32#include <asm/tlbflush.h>3334/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/35/* Data structures and variables */36/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/3738/*39* For flush_cache_all()40*/41static DEFINE_SPINLOCK(flushcache_lock);42static volatile unsigned long flushcache_cpumask = 0;4344/*45* For flush_tlb_others()46*/47static volatile cpumask_t flush_cpumask;48static struct mm_struct *flush_mm;49static struct vm_area_struct *flush_vma;50static volatile unsigned long flush_va;51static DEFINE_SPINLOCK(tlbstate_lock);52#define FLUSH_ALL 0xffffffff5354DECLARE_PER_CPU(int, prof_multiplier);55DECLARE_PER_CPU(int, prof_old_multiplier);56DECLARE_PER_CPU(int, prof_counter);5758extern spinlock_t ipi_lock[];5960/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/61/* Function Prototypes */62/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/6364void smp_reschedule_interrupt(void);65void smp_flush_cache_all_interrupt(void);6667static void flush_tlb_all_ipi(void *);68static void flush_tlb_others(cpumask_t, struct mm_struct *,69struct vm_area_struct *, unsigned long);7071void smp_invalidate_interrupt(void);7273static void stop_this_cpu(void *);7475void smp_ipi_timer_interrupt(struct pt_regs *);76void smp_local_timer_interrupt(void);7778static void send_IPI_allbutself(int, int);79static void send_IPI_mask(const struct cpumask *, int, int);8081/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/82/* Rescheduling request Routines */83/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/8485/*==========================================================================*86* Name: smp_send_reschedule87*88* Description: This routine requests other CPU to execute rescheduling.89* 1.Send 'RESCHEDULE_IPI' to other CPU.90* Request other CPU to execute 'smp_reschedule_interrupt()'.91*92* Born on Date: 2002.02.0593*94* Arguments: cpu_id - Target CPU ID95*96* Returns: void (cannot fail)97*98* Modification log:99* Date Who Description100* ---------- --- --------------------------------------------------------101*102*==========================================================================*/103void smp_send_reschedule(int cpu_id)104{105WARN_ON(cpu_is_offline(cpu_id));106send_IPI_mask(cpumask_of(cpu_id), RESCHEDULE_IPI, 1);107}108109/*==========================================================================*110* Name: smp_reschedule_interrupt111*112* Description: This routine executes on CPU which received113* 'RESCHEDULE_IPI'.114*115* Born on Date: 2002.02.05116*117* Arguments: NONE118*119* Returns: void (cannot fail)120*121* Modification log:122* Date Who Description123* ---------- --- --------------------------------------------------------124*125*==========================================================================*/126void smp_reschedule_interrupt(void)127{128scheduler_ipi();129}130131/*==========================================================================*132* Name: smp_flush_cache_all133*134* Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other135* CPUs in the system.136*137* Born on Date: 2003-05-28138*139* Arguments: NONE140*141* Returns: void (cannot fail)142*143* Modification log:144* Date Who Description145* ---------- --- --------------------------------------------------------146*147*==========================================================================*/148void smp_flush_cache_all(void)149{150cpumask_t cpumask;151unsigned long *mask;152153preempt_disable();154cpumask_copy(&cpumask, cpu_online_mask);155cpumask_clear_cpu(smp_processor_id(), &cpumask);156spin_lock(&flushcache_lock);157mask=cpumask_bits(&cpumask);158atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);159send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);160_flush_cache_copyback_all();161while (flushcache_cpumask)162mb();163spin_unlock(&flushcache_lock);164preempt_enable();165}166167void smp_flush_cache_all_interrupt(void)168{169_flush_cache_copyback_all();170clear_bit(smp_processor_id(), &flushcache_cpumask);171}172173/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/174/* TLB flush request Routines */175/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/176177/*==========================================================================*178* Name: smp_flush_tlb_all179*180* Description: This routine flushes all processes TLBs.181* 1.Request other CPU to execute 'flush_tlb_all_ipi()'.182* 2.Execute 'do_flush_tlb_all_local()'.183*184* Born on Date: 2002.02.05185*186* Arguments: NONE187*188* Returns: void (cannot fail)189*190* Modification log:191* Date Who Description192* ---------- --- --------------------------------------------------------193*194*==========================================================================*/195void smp_flush_tlb_all(void)196{197unsigned long flags;198199preempt_disable();200local_irq_save(flags);201__flush_tlb_all();202local_irq_restore(flags);203smp_call_function(flush_tlb_all_ipi, NULL, 1);204preempt_enable();205}206207/*==========================================================================*208* Name: flush_tlb_all_ipi209*210* Description: This routine flushes all local TLBs.211* 1.Execute 'do_flush_tlb_all_local()'.212*213* Born on Date: 2002.02.05214*215* Arguments: *info - not used216*217* Returns: void (cannot fail)218*219* Modification log:220* Date Who Description221* ---------- --- --------------------------------------------------------222*223*==========================================================================*/224static void flush_tlb_all_ipi(void *info)225{226__flush_tlb_all();227}228229/*==========================================================================*230* Name: smp_flush_tlb_mm231*232* Description: This routine flushes the specified mm context TLB's.233*234* Born on Date: 2002.02.05235*236* Arguments: *mm - a pointer to the mm struct for flush TLB237*238* Returns: void (cannot fail)239*240* Modification log:241* Date Who Description242* ---------- --- --------------------------------------------------------243*244*==========================================================================*/245void smp_flush_tlb_mm(struct mm_struct *mm)246{247int cpu_id;248cpumask_t cpu_mask;249unsigned long *mmc;250unsigned long flags;251252preempt_disable();253cpu_id = smp_processor_id();254mmc = &mm->context[cpu_id];255cpumask_copy(&cpu_mask, mm_cpumask(mm));256cpumask_clear_cpu(cpu_id, &cpu_mask);257258if (*mmc != NO_CONTEXT) {259local_irq_save(flags);260*mmc = NO_CONTEXT;261if (mm == current->mm)262activate_context(mm);263else264cpumask_clear_cpu(cpu_id, mm_cpumask(mm));265local_irq_restore(flags);266}267if (!cpumask_empty(&cpu_mask))268flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);269270preempt_enable();271}272273/*==========================================================================*274* Name: smp_flush_tlb_range275*276* Description: This routine flushes a range of pages.277*278* Born on Date: 2002.02.05279*280* Arguments: *mm - a pointer to the mm struct for flush TLB281* start - not used282* end - not used283*284* Returns: void (cannot fail)285*286* Modification log:287* Date Who Description288* ---------- --- --------------------------------------------------------289*290*==========================================================================*/291void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,292unsigned long end)293{294smp_flush_tlb_mm(vma->vm_mm);295}296297/*==========================================================================*298* Name: smp_flush_tlb_page299*300* Description: This routine flushes one page.301*302* Born on Date: 2002.02.05303*304* Arguments: *vma - a pointer to the vma struct include va305* va - virtual address for flush TLB306*307* Returns: void (cannot fail)308*309* Modification log:310* Date Who Description311* ---------- --- --------------------------------------------------------312*313*==========================================================================*/314void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)315{316struct mm_struct *mm = vma->vm_mm;317int cpu_id;318cpumask_t cpu_mask;319unsigned long *mmc;320unsigned long flags;321322preempt_disable();323cpu_id = smp_processor_id();324mmc = &mm->context[cpu_id];325cpumask_copy(&cpu_mask, mm_cpumask(mm));326cpumask_clear_cpu(cpu_id, &cpu_mask);327328#ifdef DEBUG_SMP329if (!mm)330BUG();331#endif332333if (*mmc != NO_CONTEXT) {334local_irq_save(flags);335va &= PAGE_MASK;336va |= (*mmc & MMU_CONTEXT_ASID_MASK);337__flush_tlb_page(va);338local_irq_restore(flags);339}340if (!cpumask_empty(&cpu_mask))341flush_tlb_others(cpu_mask, mm, vma, va);342343preempt_enable();344}345346/*==========================================================================*347* Name: flush_tlb_others348*349* Description: This routine requests other CPU to execute flush TLB.350* 1.Setup parameters.351* 2.Send 'INVALIDATE_TLB_IPI' to other CPU.352* Request other CPU to execute 'smp_invalidate_interrupt()'.353* 3.Wait for other CPUs operation finished.354*355* Born on Date: 2002.02.05356*357* Arguments: cpumask - bitmap of target CPUs358* *mm - a pointer to the mm struct for flush TLB359* *vma - a pointer to the vma struct include va360* va - virtual address for flush TLB361*362* Returns: void (cannot fail)363*364* Modification log:365* Date Who Description366* ---------- --- --------------------------------------------------------367*368*==========================================================================*/369static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,370struct vm_area_struct *vma, unsigned long va)371{372unsigned long *mask;373#ifdef DEBUG_SMP374unsigned long flags;375__save_flags(flags);376if (!(flags & 0x0040)) /* Interrupt Disable NONONO */377BUG();378#endif /* DEBUG_SMP */379380/*381* A couple of (to be removed) sanity checks:382*383* - we do not send IPIs to not-yet booted CPUs.384* - current CPU must not be in mask385* - mask must exist :)386*/387BUG_ON(cpumask_empty(&cpumask));388389BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));390BUG_ON(!mm);391392/* If a CPU which we ran on has gone down, OK. */393cpumask_and(&cpumask, &cpumask, cpu_online_mask);394if (cpumask_empty(&cpumask))395return;396397/*398* i'm not happy about this global shared spinlock in the399* MM hot path, but we'll see how contended it is.400* Temporarily this turns IRQs off, so that lockups are401* detected by the NMI watchdog.402*/403spin_lock(&tlbstate_lock);404405flush_mm = mm;406flush_vma = vma;407flush_va = va;408mask=cpumask_bits(&cpumask);409atomic_set_mask(*mask, (atomic_t *)&flush_cpumask);410411/*412* We have to send the IPI only to413* CPUs affected.414*/415send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);416417while (!cpumask_empty((cpumask_t*)&flush_cpumask)) {418/* nothing. lockup detection does not belong here */419mb();420}421422flush_mm = NULL;423flush_vma = NULL;424flush_va = 0;425spin_unlock(&tlbstate_lock);426}427428/*==========================================================================*429* Name: smp_invalidate_interrupt430*431* Description: This routine executes on CPU which received432* 'INVALIDATE_TLB_IPI'.433* 1.Flush local TLB.434* 2.Report flush TLB process was finished.435*436* Born on Date: 2002.02.05437*438* Arguments: NONE439*440* Returns: void (cannot fail)441*442* Modification log:443* Date Who Description444* ---------- --- --------------------------------------------------------445*446*==========================================================================*/447void smp_invalidate_interrupt(void)448{449int cpu_id = smp_processor_id();450unsigned long *mmc = &flush_mm->context[cpu_id];451452if (!cpumask_test_cpu(cpu_id, &flush_cpumask))453return;454455if (flush_va == FLUSH_ALL) {456*mmc = NO_CONTEXT;457if (flush_mm == current->active_mm)458activate_context(flush_mm);459else460cpumask_clear_cpu(cpu_id, mm_cpumask(flush_mm));461} else {462unsigned long va = flush_va;463464if (*mmc != NO_CONTEXT) {465va &= PAGE_MASK;466va |= (*mmc & MMU_CONTEXT_ASID_MASK);467__flush_tlb_page(va);468}469}470cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask);471}472473/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/474/* Stop CPU request Routines */475/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/476477/*==========================================================================*478* Name: smp_send_stop479*480* Description: This routine requests stop all CPUs.481* 1.Request other CPU to execute 'stop_this_cpu()'.482*483* Born on Date: 2002.02.05484*485* Arguments: NONE486*487* Returns: void (cannot fail)488*489* Modification log:490* Date Who Description491* ---------- --- --------------------------------------------------------492*493*==========================================================================*/494void smp_send_stop(void)495{496smp_call_function(stop_this_cpu, NULL, 0);497}498499/*==========================================================================*500* Name: stop_this_cpu501*502* Description: This routine halt CPU.503*504* Born on Date: 2002.02.05505*506* Arguments: NONE507*508* Returns: void (cannot fail)509*510* Modification log:511* Date Who Description512* ---------- --- --------------------------------------------------------513*514*==========================================================================*/515static void stop_this_cpu(void *dummy)516{517int cpu_id = smp_processor_id();518519/*520* Remove this CPU:521*/522set_cpu_online(cpu_id, false);523524/*525* PSW IE = 1;526* IMASK = 0;527* goto SLEEP528*/529local_irq_disable();530outl(0, M32R_ICU_IMASK_PORTL);531inl(M32R_ICU_IMASK_PORTL); /* dummy read */532local_irq_enable();533534for ( ; ; );535}536537void arch_send_call_function_ipi_mask(const struct cpumask *mask)538{539send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);540}541542void arch_send_call_function_single_ipi(int cpu)543{544send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI, 0);545}546547/*==========================================================================*548* Name: smp_call_function_interrupt549*550* Description: This routine executes on CPU which received551* 'CALL_FUNCTION_IPI'.552*553* Born on Date: 2002.02.05554*555* Arguments: NONE556*557* Returns: void (cannot fail)558*559* Modification log:560* Date Who Description561* ---------- --- --------------------------------------------------------562*563*==========================================================================*/564void smp_call_function_interrupt(void)565{566irq_enter();567generic_smp_call_function_interrupt();568irq_exit();569}570571void smp_call_function_single_interrupt(void)572{573irq_enter();574generic_smp_call_function_single_interrupt();575irq_exit();576}577578/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/579/* Timer Routines */580/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/581582/*==========================================================================*583* Name: smp_send_timer584*585* Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs586* in the system.587*588* Born on Date: 2002.02.05589*590* Arguments: NONE591*592* Returns: void (cannot fail)593*594* Modification log:595* Date Who Description596* ---------- --- --------------------------------------------------------597*598*==========================================================================*/599void smp_send_timer(void)600{601send_IPI_allbutself(LOCAL_TIMER_IPI, 1);602}603604/*==========================================================================*605* Name: smp_send_timer606*607* Description: This routine executes on CPU which received608* 'LOCAL_TIMER_IPI'.609*610* Born on Date: 2002.02.05611*612* Arguments: *regs - a pointer to the saved regster info613*614* Returns: void (cannot fail)615*616* Modification log:617* Date Who Description618* ---------- --- --------------------------------------------------------619*620*==========================================================================*/621void smp_ipi_timer_interrupt(struct pt_regs *regs)622{623struct pt_regs *old_regs;624old_regs = set_irq_regs(regs);625irq_enter();626smp_local_timer_interrupt();627irq_exit();628set_irq_regs(old_regs);629}630631/*==========================================================================*632* Name: smp_local_timer_interrupt633*634* Description: Local timer interrupt handler. It does both profiling and635* process statistics/rescheduling.636* We do profiling in every local tick, statistics/rescheduling637* happen only every 'profiling multiplier' ticks. The default638* multiplier is 1 and it can be changed by writing the new639* multiplier value into /proc/profile.640*641* Born on Date: 2002.02.05642*643* Arguments: *regs - a pointer to the saved regster info644*645* Returns: void (cannot fail)646*647* Original: arch/i386/kernel/apic.c648*649* Modification log:650* Date Who Description651* ---------- --- --------------------------------------------------------652* 2003-06-24 hy use per_cpu structure.653*==========================================================================*/654void smp_local_timer_interrupt(void)655{656int user = user_mode(get_irq_regs());657int cpu_id = smp_processor_id();658659/*660* The profiling function is SMP safe. (nothing can mess661* around with "current", and the profiling counters are662* updated with atomic operations). This is especially663* useful with a profiling multiplier != 1664*/665666profile_tick(CPU_PROFILING);667668if (--per_cpu(prof_counter, cpu_id) <= 0) {669/*670* The multiplier may have changed since the last time we got671* to this point as a result of the user writing to672* /proc/profile. In this case we need to adjust the APIC673* timer accordingly.674*675* Interrupts are already masked off at this point.676*/677per_cpu(prof_counter, cpu_id)678= per_cpu(prof_multiplier, cpu_id);679if (per_cpu(prof_counter, cpu_id)680!= per_cpu(prof_old_multiplier, cpu_id))681{682per_cpu(prof_old_multiplier, cpu_id)683= per_cpu(prof_counter, cpu_id);684}685686update_process_times(user);687}688}689690/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/691/* Send IPI Routines */692/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/693694/*==========================================================================*695* Name: send_IPI_allbutself696*697* Description: This routine sends a IPI to all other CPUs in the system.698*699* Born on Date: 2002.02.05700*701* Arguments: ipi_num - Number of IPI702* try - 0 : Send IPI certainly.703* !0 : The following IPI is not sent when Target CPU704* has not received the before IPI.705*706* Returns: void (cannot fail)707*708* Modification log:709* Date Who Description710* ---------- --- --------------------------------------------------------711*712*==========================================================================*/713static void send_IPI_allbutself(int ipi_num, int try)714{715cpumask_t cpumask;716717cpumask_copy(&cpumask, cpu_online_mask);718cpumask_clear_cpu(smp_processor_id(), &cpumask);719720send_IPI_mask(&cpumask, ipi_num, try);721}722723/*==========================================================================*724* Name: send_IPI_mask725*726* Description: This routine sends a IPI to CPUs in the system.727*728* Born on Date: 2002.02.05729*730* Arguments: cpu_mask - Bitmap of target CPUs logical ID731* ipi_num - Number of IPI732* try - 0 : Send IPI certainly.733* !0 : The following IPI is not sent when Target CPU734* has not received the before IPI.735*736* Returns: void (cannot fail)737*738* Modification log:739* Date Who Description740* ---------- --- --------------------------------------------------------741*742*==========================================================================*/743static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)744{745cpumask_t physid_mask, tmp;746int cpu_id, phys_id;747int num_cpus = num_online_cpus();748749if (num_cpus <= 1) /* NO MP */750return;751752cpumask_and(&tmp, cpumask, cpu_online_mask);753BUG_ON(!cpumask_equal(cpumask, &tmp));754755cpumask_clear(&physid_mask);756for_each_cpu(cpu_id, cpumask) {757if ((phys_id = cpu_to_physid(cpu_id)) != -1)758cpumask_set_cpu(phys_id, &physid_mask);759}760761send_IPI_mask_phys(&physid_mask, ipi_num, try);762}763764/*==========================================================================*765* Name: send_IPI_mask_phys766*767* Description: This routine sends a IPI to other CPUs in the system.768*769* Born on Date: 2002.02.05770*771* Arguments: cpu_mask - Bitmap of target CPUs physical ID772* ipi_num - Number of IPI773* try - 0 : Send IPI certainly.774* !0 : The following IPI is not sent when Target CPU775* has not received the before IPI.776*777* Returns: IPICRi regster value.778*779* Modification log:780* Date Who Description781* ---------- --- --------------------------------------------------------782*783*==========================================================================*/784unsigned long send_IPI_mask_phys(const cpumask_t *physid_mask, int ipi_num,785int try)786{787spinlock_t *ipilock;788volatile unsigned long *ipicr_addr;789unsigned long ipicr_val;790unsigned long my_physid_mask;791unsigned long mask = cpumask_bits(physid_mask)[0];792793794if (mask & ~physids_coerce(phys_cpu_present_map))795BUG();796if (ipi_num >= NR_IPIS || ipi_num < 0)797BUG();798799mask <<= IPI_SHIFT;800ipilock = &ipi_lock[ipi_num];801ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR802+ (ipi_num << 2));803my_physid_mask = ~(1 << smp_processor_id());804805/*806* lock ipi_lock[i]807* check IPICRi == 0808* write IPICRi (send IPIi)809* unlock ipi_lock[i]810*/811spin_lock(ipilock);812__asm__ __volatile__ (813";; CHECK IPICRi == 0 \n\t"814".fillinsn \n"815"1: \n\t"816"ld %0, @%1 \n\t"817"and %0, %4 \n\t"818"beqz %0, 2f \n\t"819"bnez %3, 3f \n\t"820"bra 1b \n\t"821";; WRITE IPICRi (send IPIi) \n\t"822".fillinsn \n"823"2: \n\t"824"st %2, @%1 \n\t"825".fillinsn \n"826"3: \n\t"827: "=&r"(ipicr_val)828: "r"(ipicr_addr), "r"(mask), "r"(try), "r"(my_physid_mask)829: "memory"830);831spin_unlock(ipilock);832833return ipicr_val;834}835836837