📄 smtc.c
字号:
/* Copyright (C) 2004 Mips Technologies, Inc */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/cpumask.h>#include <linux/interrupt.h>#include <asm/cpu.h>#include <asm/processor.h>#include <asm/atomic.h>#include <asm/system.h>#include <asm/hardirq.h>#include <asm/hazards.h>#include <asm/mmu_context.h>#include <asm/smp.h>#include <asm/mipsregs.h>#include <asm/cacheflush.h>#include <asm/time.h>#include <asm/addrspace.h>#include <asm/smtc.h>#include <asm/smtc_ipi.h>#include <asm/smtc_proc.h>/* * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. *//* * MIPSCPU_INT_BASE is identically defined in both * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h, * but as yet there's no properly organized include structure that * will ensure that the right *int.h file will be included for a * given platform build. */#define MIPSCPU_INT_BASE 16#define MIPS_CPU_IPI_IRQ 1#define LOCK_MT_PRA() \ local_irq_save(flags); \ mtflags = dmt()#define UNLOCK_MT_PRA() \ emt(mtflags); \ local_irq_restore(flags)#define LOCK_CORE_PRA() \ local_irq_save(flags); \ mtflags = dvpe()#define UNLOCK_CORE_PRA() \ evpe(mtflags); \ local_irq_restore(flags)/* * Data structures purely associated with SMTC parallelism *//* * Table for tracking ASIDs whose lifetime is prolonged. */asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];/* * Clock interrupt "latch" buffers, per "CPU" */unsigned int ipi_timer_latch[NR_CPUS];/* * Number of InterProcessor Interupt (IPI) message buffers to allocate */#define IPIBUF_PER_CPU 4struct smtc_ipi_q IPIQ[NR_CPUS];struct smtc_ipi_q freeIPIq;/* Forward declarations */void ipi_decode(struct pt_regs *, struct smtc_ipi *);void post_direct_ipi(int cpu, struct smtc_ipi *pipi);void setup_cross_vpe_interrupts(void);void init_smtc_stats(void);/* Global SMTC Status */unsigned int smtc_status = 0;/* Boot command line configuration overrides */static int vpelimit = 0;static int tclimit = 0;static int ipibuffers = 0;static int nostlb = 0;static int asidmask = 0;unsigned long smtc_asid_mask = 0xff;static int __init maxvpes(char *str){ get_option(&str, &vpelimit); return 1;}static int __init maxtcs(char *str){ get_option(&str, &tclimit); return 1;}static int __init ipibufs(char *str){ get_option(&str, &ipibuffers); return 1;}static int __init stlb_disable(char *s){ nostlb = 1; return 1;}static int __init asidmask_set(char *str){ get_option(&str, &asidmask); switch(asidmask) { case 0x1: case 0x3: case 0x7: case 0xf: case 0x1f: case 0x3f: case 0x7f: case 0xff: smtc_asid_mask = (unsigned long)asidmask; break; default: printk("ILLEGAL ASID mask 0x%x from command line\n", asidmask); } return 1;}__setup("maxvpes=", maxvpes);__setup("maxtcs=", maxtcs);__setup("ipibufs=", ipibufs);__setup("nostlb", stlb_disable);__setup("asidmask=", asidmask_set);/* Enable additional debug checks before going into CPU idle loop */#define SMTC_IDLE_HOOK_DEBUG#ifdef SMTC_IDLE_HOOK_DEBUGstatic int hang_trig = 0;static int __init hangtrig_enable(char *s){ hang_trig = 1; return 1;}__setup("hangtrig", hangtrig_enable);#define DEFAULT_BLOCKED_IPI_LIMIT 32static int timerq_limit = DEFAULT_BLOCKED_IPI_LIMIT;static int __init tintq(char *str){ get_option(&str, &timerq_limit); return 1;}__setup("tintq=", tintq);int imstuckcount[2][8];/* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */int vpemask[2][8] = {{0,1,1,0,0,0,0,1},{0,1,0,0,0,0,0,1}};int tcnoprog[NR_CPUS];static atomic_t idle_hook_initialized = {0};static int clock_hang_reported[NR_CPUS];#endif /* SMTC_IDLE_HOOK_DEBUG *//* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */void __init sanitize_tlb_entries(void){ printk("Deprecated sanitize_tlb_entries() invoked\n");}/* * Configure shared TLB - VPC configuration bit must be set by caller */void smtc_configure_tlb(void){ int i,tlbsiz,vpes; unsigned long mvpconf0; unsigned long config1val; /* Set up ASID preservation table */ for (vpes=0; vpes<MAX_SMTC_TLBS; vpes++) { for(i = 0; i < MAX_SMTC_ASIDS; i++) { smtc_live_asid[vpes][i] = 0; } } mvpconf0 = read_c0_mvpconf0(); if ((vpes = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) > 1) { /* If we have multiple VPEs, try to share the TLB */ if ((mvpconf0 & MVPCONF0_TLBS) && !nostlb) { /* * If TLB sizing is programmable, shared TLB * size is the total available complement. * Otherwise, we have to take the sum of all * static VPE TLB entries. */ if ((tlbsiz = ((mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT)) == 0) { /* * If there's more than one VPE, there had better * be more than one TC, because we need one to bind * to each VPE in turn to be able to read * its configuration state! */ settc(1); /* Stop the TC from doing anything foolish */ write_tc_c0_tchalt(TCHALT_H); mips_ihb(); /* No need to un-Halt - that happens later anyway */ for (i=0; i < vpes; i++) { write_tc_c0_tcbind(i); /* * To be 100% sure we're really getting the right * information, we exit the configuration state * and do an IHB after each rebinding. */ write_c0_mvpcontrol( read_c0_mvpcontrol() & ~ MVPCONTROL_VPC ); mips_ihb(); /* * Only count if the MMU Type indicated is TLB */ if(((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) { config1val = read_vpe_c0_config1(); tlbsiz += ((config1val >> 25) & 0x3f) + 1; } /* Put core back in configuration state */ write_c0_mvpcontrol( read_c0_mvpcontrol() | MVPCONTROL_VPC ); mips_ihb(); } } write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB); /* * Setup kernel data structures to use software total, * rather than read the per-VPE Config1 value. The values * for "CPU 0" gets copied to all the other CPUs as part * of their initialization in smtc_cpu_setup(). */ tlbsiz = tlbsiz & 0x3f; /* MIPS32 limits TLB indices to 64 */ cpu_data[0].tlbsize = tlbsiz; smtc_status |= SMTC_TLB_SHARED; printk("TLB of %d entry pairs shared by %d VPEs\n", tlbsiz, vpes); } else { printk("WARNING: TLB Not Sharable on SMTC Boot!\n"); } }}/* * Incrementally build the CPU map out of constituent MIPS MT cores, * using the specified available VPEs and TCs. Plaform code needs * to ensure that each MIPS MT core invokes this routine on reset, * one at a time(!). * * This version of the build_cpu_map and prepare_cpus routines assumes * that *all* TCs of a MIPS MT core will be used for Linux, and that * they will be spread across *all* available VPEs (to minimise the * loss of efficiency due to exception service serialization). * An improved version would pick up configuration information and * possibly leave some TCs/VPEs as "slave" processors. * * Use c0_MVPConf0 to find out how many TCs are available, setting up * phys_cpu_present_map and the logical/physical mappings. */int __init mipsmt_build_cpu_map(int start_cpu_slot){ int i, ntcs; /* * The CPU map isn't actually used for anything at this point, * so it's not clear what else we should do apart from set * everything up so that "logical" = "physical". */ ntcs = ((read_c0_mvpconf0() & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; for (i=start_cpu_slot; i<NR_CPUS && i<ntcs; i++) { cpu_set(i, phys_cpu_present_map); __cpu_number_map[i] = i; __cpu_logical_map[i] = i; } /* Initialize map of CPUs with FPUs */ cpus_clear(mt_fpu_cpumask); /* One of those TC's is the one booting, and not a secondary... */ printk("%i available secondary CPU TC(s)\n", i - 1); return i;}/* * Common setup before any secondaries are started * Make sure all CPU's are in a sensible state before we boot any of the * secondaries. * * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly * as possible across the available VPEs. */static void smtc_tc_setup(int vpe, int tc, int cpu){ settc(tc); write_tc_c0_tchalt(TCHALT_H); mips_ihb(); write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A); write_tc_c0_tccontext(0); /* Bind tc to vpe */ write_tc_c0_tcbind(vpe); /* In general, all TCs should have the same cpu_data indications */ memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ if (cpu_data[0].cputype == CPU_34K) cpu_data[cpu].options &= ~MIPS_CPU_FPU; cpu_data[cpu].vpe_id = vpe; cpu_data[cpu].tc_id = tc;}void mipsmt_prepare_cpus(void){ int i, vpe, tc, ntc, nvpe, tcpervpe, slop, cpu; unsigned long flags; unsigned long val; int nipi; struct smtc_ipi *pipi; /* disable interrupts so we can disable MT */ local_irq_save(flags); /* disable MT so we can configure */ dvpe(); dmt(); freeIPIq.lock = SPIN_LOCK_UNLOCKED; /* * We probably don't have as many VPEs as we do SMP "CPUs", * but it's possible - and in any case we'll never use more! */ for (i=0; i<NR_CPUS; i++) { IPIQ[i].head = IPIQ[i].tail = NULL; IPIQ[i].lock = SPIN_LOCK_UNLOCKED; IPIQ[i].depth = 0; ipi_timer_latch[i] = 0; } /* cpu_data index starts at zero */ cpu = 0; cpu_data[cpu].vpe_id = 0; cpu_data[cpu].tc_id = 0; cpu++; /* Report on boot-time options */ mips_mt_set_cpuoptions (); if (vpelimit > 0) printk("Limit of %d VPEs set\n", vpelimit); if (tclimit > 0) printk("Limit of %d TCs set\n", tclimit); if (nostlb) { printk("Shared TLB Use Inhibited - UNSAFE for Multi-VPE Operation\n"); } if (asidmask) printk("ASID mask value override to 0x%x\n", asidmask); /* Temporary */#ifdef SMTC_IDLE_HOOK_DEBUG if (hang_trig) printk("Logic Analyser Trigger on suspected TC hang\n");#endif /* SMTC_IDLE_HOOK_DEBUG */ /* Put MVPE's into 'configuration state' */ write_c0_mvpcontrol( read_c0_mvpcontrol() | MVPCONTROL_VPC ); val = read_c0_mvpconf0(); nvpe = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; if (vpelimit > 0 && nvpe > vpelimit) nvpe = vpelimit; ntc = ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; if (ntc > NR_CPUS) ntc = NR_CPUS; if (tclimit > 0 && ntc > tclimit) ntc = tclimit; tcpervpe = ntc / nvpe; slop = ntc % nvpe; /* Residual TCs, < NVPE */ /* Set up shared TLB */ smtc_configure_tlb(); for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) { /* * Set the MVP bits. */ settc(tc); write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_MVP); if (vpe != 0) printk(", "); printk("VPE %d: TC", vpe); for (i = 0; i < tcpervpe; i++) { /* * TC 0 is bound to VPE 0 at reset, * and is presumably executing this * code. Leave it alone! */ if (tc != 0) { smtc_tc_setup(vpe,tc, cpu);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -