--- zzzz-none-000/linux-2.6.32.61/arch/mips/kernel/vpe.c 2013-06-10 09:43:48.000000000 +0000 +++ ar10-7272-687/linux-2.6.32.61/arch/mips/kernel/vpe.c 2011-07-22 09:48:51.000000000 +0000 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,8 @@ #include #include #include +#include +#include typedef void *vpe_handle; @@ -74,9 +77,78 @@ #ifdef CONFIG_MIPS_APSP_KSPD static struct kspd_notifications kspd_events; -static int kspd_events_reqd; +static int kspd_events_reqd = 0; #endif +#ifdef CONFIG_IFX_VPE_EXT +static int is_sdepgm; +extern int stlb; +extern int vpe0_wired; +extern int vpe1_wired; +unsigned int vpe1_load_addr; + +//kishore +//#define set_c0_mvpcontrol(MVPCONTROL_VPC) write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); ehb(); + +//#define clear_c0_mvpcontrol(MVPCONTROL_VPC) write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); ehb(); + + + +static int __init load_address(char *str) +{ + get_option(&str, &vpe1_load_addr); + return 1; +} + +__setup("vpe1_load_addr=", load_address); + +#include +#include +char command_line[COMMAND_LINE_SIZE * 2]; +extern char *saved_command_line; +static unsigned int vpe1_mem; +static void __init vpe1mem(void) +{ + char *ptr; + ptr = strstr(command_line, "vpe1_mem="); + + if (ptr && (ptr != command_line) && (*(ptr - 1) != ' ')) + ptr = strstr(ptr, " vpe1_mem="); + + if (ptr) + vpe1_mem = memparse(ptr + 9, &ptr); + printk("vpe1_mem = %x\n", vpe1_mem); +} + +uint32_t vpe1_wdog_ctr; +static int __init wdog_ctr(char *str) +{ + get_option(&str, &vpe1_wdog_ctr); + return 1; +} + +__setup("vpe1_wdog_ctr_addr=", wdog_ctr); +EXPORT_SYMBOL(vpe1_wdog_ctr); + +uint32_t vpe1_wdog_timeout; +static int __init wdog_timeout(char *str) +{ + get_option(&str, &vpe1_wdog_timeout); + return 1; +} + +__setup("vpe1_wdog_timeout=", wdog_timeout); +EXPORT_SYMBOL(vpe1_wdog_timeout); + +#endif + +#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ +extern int vpe_icache_shared,vpe_dcache_shared; +extern int icache_way0,icache_way1,icache_way2,icache_way3; +extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3; +#endif + + /* grab the likely amount of memory we will need. */ #ifdef CONFIG_MIPS_VPE_LOADER_TOM #define P_SIZE (2 * 1024 * 1024) @@ -193,7 +265,7 @@ } spin_unlock(&vpecontrol.tc_list_lock); - return NULL; + return res; } /* allocate a vpe and associate it with this minor (or index) */ @@ -273,8 +345,19 @@ * This means you must tell Linux to use less memory than you * physically have, for example by passing a mem= boot argument. */ +#ifdef CONFIG_IFX_VPE_EXT + if (vpe1_load_addr){ + //printk ("vpe1_load_addr = 0x%x\n", vpe1_load_addr); + return (void *)vpe1_load_addr; + + } + else { +#endif addr = pfn_to_kaddr(max_low_pfn); memset(addr, 0, len); +#ifdef CONFIG_IFX_VPE_EXT + } +#endif #else /* simple grab some mem for now */ addr = kzalloc(len, GFP_KERNEL); @@ -746,6 +829,21 @@ return -ENOEXEC; } +#ifdef CONFIG_IFX_VPE_EXT + if (stlb) + write_vpe_c0_wired(vpe0_wired + vpe1_wired); + else + write_vpe_c0_wired(vpe1_wired); + //Check whether we need to convert to KSEG1ADDR or not + #if 0 + if (vpe1_load_addr) + // write_tc_c0_tcrestart((unsigned long)vpe1_load_addr); + write_tc_c0_tcrestart((unsigned long)KSEG1ADDR(vpe1_load_addr)); + else + #endif +#endif + + printk(KERN_WARNING "%s: tc %d start-addr %lx\n", __func__, t->index, v->__start); /* Write the address we want it to start running from in the TCPC register. */ write_tc_c0_tcrestart((unsigned long)v->__start); write_tc_c0_tccontext((unsigned long)0); @@ -758,8 +856,30 @@ val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; write_tc_c0_tcstatus(val); + printk(KERN_WARNING "%s: tc %d tcstatus %08lx tcbind %08lx\n MVPCONTROL %08x vpeopt %08x\n", + __func__, + t->index, + read_tc_c0_tcstatus(), + read_tc_c0_tcbind(), + read_c0_mvpcontrol(), + __read_32bit_c0_register($1,7)); write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); + mips_ihb(); +#ifdef CONFIG_IFX_VPE_EXT + /* + * $a2 & $a3 are used to pass command line parameters to VPE1. $a2 + * points to the start of the command line string and $a3 points to + * the end of the string. This convention is identical to the Linux + * kernel boot parameter passing mechanism. Please note that $a3 is + * used to pass physical memory size or 0 in SDE tool kit. So, if you + * are passing comand line parameters through $a2 & $a3 SDE programs + * don't work as desired. + */ + mttgpr(6, command_line); + mttgpr(7, (command_line + strlen(command_line))); + if (is_sdepgm) { +#endif /* * The sde-kit passes 'memsize' to __start in $a3, so set something * here... Or set $a3 to zero and define DFLT_STACK_SIZE and @@ -767,7 +887,9 @@ */ mttgpr(6, v->ntcs); mttgpr(7, physical_memsize); - +#ifdef CONFIG_IFX_VPE_EXT + } +#endif /* set up VPE1 */ /* * bind the TC to VPE 1 as late as possible so we only have the final @@ -788,6 +910,66 @@ /* enable this VPE */ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); +#ifdef CONFIG_IFX_VPE_CACHE_SPLIT + if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) { + + /* PCP bit must be 1 to split the cache */ + if(read_c0_mvpconf0() & MVPCONF0_PCP) { + + if ( !vpe_icache_shared ){ + write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS); + + /* + * If any cache way is 1, then that way is denied + * in VPE1. Otherwise assign that way to VPE1. + */ + if (!icache_way0) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 ); + if (!icache_way1) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 ); + if (!icache_way2) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 ); + if (!icache_way3) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 ); + } + + if ( !vpe_dcache_shared ) { + write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS); + + /* + * If any cache way is 1, then that way is denied + * in VPE1. Otherwise assign that way to VPE1. + */ + if (!dcache_way0) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 ); + if (!dcache_way1) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 ); + if (!dcache_way2) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 ); + if (!dcache_way3) + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 ); + else + write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 ); + } + } + } + +#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ + /* clear out any left overs from a previous program */ write_vpe_c0_status(0); write_vpe_c0_cause(0); @@ -834,6 +1016,10 @@ if ( (v->__start == 0) || (v->shared_ptr == NULL)) return -1; +#ifdef CONFIG_IFX_VPE_EXT + is_sdepgm = 1; +#endif + return 0; } @@ -914,9 +1100,10 @@ if (!v->load_addr) return -ENOMEM; - pr_info("VPE loader: loading to %p\n", v->load_addr); if (relocate) { + pr_info("VPE loader: loading to base %p (relocateable)\n", v->load_addr); + for (i = 0; i < hdr->e_shnum; i++) { void *dest; @@ -962,16 +1149,24 @@ return err; } + /* make sure it's physically written out */ + flush_icache_range((unsigned long)v->load_addr, (unsigned long)v->load_addr + v->len); } else { struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff); + for (i = 0; i < hdr->e_phnum; i++) { if (phdr->p_type == PT_LOAD) { + pr_info("VPE loader: loading segment %d to %p (%x bytes)\n", i, (void *)phdr->p_paddr, phdr->p_memsz); memcpy((void *)phdr->p_paddr, (char *)hdr + phdr->p_offset, phdr->p_filesz); memset((void *)phdr->p_paddr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + if(phdr->p_memsz) { + dma_cache_wback_inv((unsigned long)phdr->p_paddr, phdr->p_memsz); + flush_icache_range((unsigned long)phdr->p_paddr, (unsigned long)phdr->p_paddr + phdr->p_memsz); + } } phdr++; } @@ -994,7 +1189,17 @@ flush_icache_range((unsigned long)v->load_addr, (unsigned long)v->load_addr + v->len); + //printk ("outside findvpesym vpe1_load_addr = %x\n", vpe1_load_addr); if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { +#ifdef CONFIG_IFX_VPE_EXT + if (vpe1_load_addr) { + //printk ("inside findvpesym vpe1_load_addr = %x", vpe1_load_addr); + /* Conversion to KSEG1 is required ??? */ + v->__start = KSEG1ADDR(vpe1_load_addr); + is_sdepgm = 0; + return 0; + } +#endif if (v->__start == 0) { printk(KERN_WARNING "VPE loader: program does not contain " "a __start symbol\n"); @@ -1065,7 +1270,9 @@ struct vpe_notifications *not; struct vpe *v; int ret; - +#ifdef CONFIG_IFX_VPE_EXT + int progsize; +#endif if (minor != iminor(inode)) { /* assume only 1 device at the moment. */ pr_warning("VPE loader: only vpe1 is supported\n"); @@ -1091,9 +1298,16 @@ cleanup_tc(get_tc(tclimit)); } +#ifdef CONFIG_IFX_VPE_EXT + progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; + //printk("progsize = %x\n", progsize); + v->pbuffer = vmalloc(progsize); + v->plen = progsize; +#else /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); v->plen = P_SIZE; +#endif v->load_addr = NULL; v->len = 0; @@ -1268,6 +1482,9 @@ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); /* halt the TC */ +#ifdef CONFIG_IFX_VPE_EXT + write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); +#endif write_tc_c0_tchalt(TCHALT_H); mips_ihb(); @@ -1352,6 +1569,134 @@ } #endif +#ifdef CONFIG_IFX_VPE_EXT +int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags) +{ + enum vpe_state state; + struct vpe *v = get_vpe(tclimit); + struct vpe_notifications *not; + + if (tcmask || flags) { + printk(KERN_WARNING "Currently tcmask and flags should be 0." + "other values not supported\n"); + return -1; + } + + state = xchg(&v->state, VPE_STATE_INUSE); + if (state != VPE_STATE_UNUSED) { + vpe_stop(v); + + list_for_each_entry(not, &v->notify, list) { + not->stop(tclimit); + } + } + + v->__start = (unsigned long)sw_start_addr; + is_sdepgm = 0; + + if (!vpe_run(v)) { + printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n"); + return 0; + } + return -1; +} + +EXPORT_SYMBOL(vpe1_sw_start); + +int32_t vpe1_sw_stop(uint32_t flags) +{ + struct vpe *v = get_vpe(tclimit); + + if (!vpe_free(v)) { + printk(KERN_DEBUG "RP Stopped\n"); + return 0; + } + else + return -1; +} + +EXPORT_SYMBOL(vpe1_sw_stop); + +uint32_t vpe1_get_load_addr (uint32_t flags) +{ + return vpe1_load_addr; +} + +EXPORT_SYMBOL(vpe1_get_load_addr); + +uint32_t vpe1_get_max_mem (uint32_t flags) +{ + if (!vpe1_mem) + return P_SIZE; + else + return vpe1_mem; +} + +EXPORT_SYMBOL(vpe1_get_max_mem); + +void* vpe1_get_cmdline_argument(void) +{ + return saved_command_line; +} + +EXPORT_SYMBOL(vpe1_get_cmdline_argument); + +int32_t vpe1_set_boot_param(char *field, char *value, char flags) +{ + char *ptr, string[64]; + int start_off, end_off; + if (!field) + return -1; + strcpy(string, field); + if (value) { + strcat(string, "="); + strcat(string, value); + strcat(command_line, " "); + strcat(command_line, string); + } + else { + ptr = strstr(command_line, string); + if (ptr) { + start_off = ptr - command_line; + ptr += strlen(string); + while ((*ptr != ' ') && (*ptr != '\0')) + ptr++; + end_off = ptr - command_line; + command_line[start_off] = '\0'; + strcat (command_line, command_line+end_off); + } + } + return 0; +} + +EXPORT_SYMBOL(vpe1_set_boot_param); + +int32_t vpe1_get_boot_param(char *field, char **value, char flags) +{ + char *ptr, string[64]; + int i = 0; + if (!field) + return -1; + if ((ptr = strstr(command_line, field))) { + ptr += strlen(field) + 1; /* including = */ + while ((*ptr != ' ') && (*ptr != '\0')) + string[i++] = *ptr++; + string[i] = '\0'; + *value = kmalloc((strlen(string) + 1), GFP_KERNEL); + if (*value != NULL) + strcpy(*value, string); + } + else + *value = NULL; + + return 0; +} + +EXPORT_SYMBOL(vpe1_get_boot_param); + +extern void configure_tlb(void); +#endif + static ssize_t store_kill(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1420,20 +1765,141 @@ struct device vpe_device; +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0) { + unsigned long tmp; + + if (!tc) { + printk("%s: tc %d tcbind %08lx tcstatus %08lx\n", __func__, tc, read_tc_c0_tcbind(), read_tc_c0_tcstatus()); + return; + } + + /* bind a TC to each VPE, May as well put all excess TC's + on the last VPE */ + if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1)) + write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); + else { + write_tc_c0_tcbind(read_tc_c0_tcbind() | tc); + + /* and set XTC */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT)); + } + + tmp = read_tc_c0_tcstatus(); + + /* mark not allocated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + + write_tc_c0_tchalt(TCHALT_H); + + printk("%s: tc %d tcbind %08lx tcstatus %08lx\n", __func__, tc, read_tc_c0_tcbind(), read_tc_c0_tcstatus()); +} +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static void __init smvp_copy_vpe_config(void) { + write_vpe_c0_status( + (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); + + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ + write_vpe_c0_config( read_c0_config()); + + /* make sure there are no software interrupts pending */ + write_vpe_c0_cause(0); + + /* Propagate Config7 */ + write_vpe_c0_config7(read_c0_config7()); + + write_vpe_c0_count(read_c0_count()); +} +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0, unsigned int ncpu) { + if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) + return ncpu; + + /* Deactivate all but VPE 0 */ + if (tc != 0) { + unsigned long tmp = read_vpe_c0_vpeconf0(); + + tmp &= ~VPECONF0_VPA; + + /* master VPE */ + tmp |= VPECONF0_MVP; + write_vpe_c0_vpeconf0(tmp); + + /* Record this as available CPU */ + /*--- cpu_set(tc, phys_cpu_present_map); ---*/ + /*--- __cpu_number_map[tc] = ++ncpu; ---*/ + /*--- __cpu_logical_map[ncpu] = tc; ---*/ + } + + /* Disable multi-threading with TC's */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); + + if (tc != 0) + smvp_copy_vpe_config(); + return ncpu; +} + static int __init vpe_module_init(void) { unsigned int mtflags, vpflags; unsigned long flags, val; struct vpe *v = NULL; struct tc *t; - int tc, err; + int tc, err = 0; +#if 0 + printk(KERN_ERR "vorher in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s \n", + in_atomic(), irqs_disabled(), get_current()->pid, get_current()->comm); + + local_irq_save(flags); + + printk("[%s] irq_flags %#x \n", __FUNCTION__, (unsigned int)flags); + printk(KERN_ERR "drin in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s \n", + in_atomic(), irqs_disabled(), get_current()->pid, get_current()->comm); + + local_irq_restore(flags); + printk(KERN_ERR "nachher in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s \n", + in_atomic(), irqs_disabled(), get_current()->pid, get_current()->comm); + +#endif if (!cpu_has_mipsmt) { printk("VPE loader: not a MIPS MT capable processor\n"); return -ENODEV; } - if (vpelimit == 0) { +#ifdef CONFIG_IFX_VPE_EXT + strcpy(command_line, saved_command_line); + vpe1mem(); +#ifndef CONFIG_MIPS_MT_SMTC + configure_tlb(); +#endif +#endif + +#ifndef CONFIG_MIPS_MT_SMTC + if (!vpelimit) + vpelimit = 1; + if (!tclimit) + tclimit = 1; +#endif + +#ifdef CONFIG_IFX_VPE_EXT + val = read_c0_mvpconf0(); + + hw_tcs = (val & MVPCONF0_PTC) + 1; + hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; + +#endif + + if (vpelimit == 0 +#ifdef CONFIG_IFX_VPE_EXT + || (vpelimit >= hw_vpes) +#endif +) { printk(KERN_WARNING "No VPEs reserved for AP/SP, not " "initializing VPE loader.\nPass maxvpes= argument as " "kernel argument\n"); @@ -1441,7 +1907,11 @@ return -ENODEV; } - if (tclimit == 0) { + if (tclimit == 0 +#ifdef CONFIG_IFX_VPE_EXT +|| (tclimit >= hw_tcs) +#endif +) { printk(KERN_WARNING "No TCs reserved for AP/SP, not " "initializing VPE loader.\nPass maxtcs= argument as " "kernel argument\n"); @@ -1475,7 +1945,10 @@ local_irq_save(flags); mtflags = dmt(); vpflags = dvpe(); - +#ifdef CONFIG_IFX_VPE_EXT + back_to_back_c0_hazard(); + val = hw_tcs = hw_vpes = 0; +#endif /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); @@ -1485,15 +1958,18 @@ hw_tcs = (val & MVPCONF0_PTC) + 1; hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; +#if 0 for (tc = tclimit; tc < hw_tcs; tc++) { /* * Must re-enable multithreading temporarily or in case we * reschedule send IPIs or similar we might hang. */ - clear_c0_mvpcontrol(MVPCONTROL_VPC); + + clear_c0_mvpcontrol(MVPCONTROL_VPC); evpe(vpflags); emt(mtflags); local_irq_restore(flags); + t = alloc_tc(tc); if (!t) { err = -ENOMEM; @@ -1509,26 +1985,60 @@ if (tc < hw_tcs) { settc(tc); - if ((v = alloc_vpe(tc)) == NULL) { - printk(KERN_WARNING "VPE: unable to allocate VPE\n"); - - goto out_reenable; - } +#if 0 + printk( KERN_ERR "[%s] alloc_vpe(tc), tc=%d\n", __FUNCTION__, tc); + printk( KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s \n", + in_atomic(), irqs_disabled(), get_current()->pid, get_current()->comm); +#endif + /*------------------------------------------------------------*\ + * Irqs wieder zulassen waehrend alloc_vpe + \*------------------------------------------------------------*/ + + clear_c0_mvpcontrol(MVPCONTROL_VPC); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); + + v = alloc_vpe(tc); + + /*------------------------------------------------------------*\ + * Irqs wieder verbieten nach alloc_vpe + \*------------------------------------------------------------*/ + + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + set_c0_mvpcontrol(MVPCONTROL_VPC); + + if (v == NULL){ + printk(KERN_WARNING "VPE: unable to allocate VPE\n"); + goto out_reenable; + } v->ntcs = hw_tcs - tclimit; + write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); + /* add the tc to the list of this vpe's tc's. */ list_add(&t->tc, &v->tc); /* deactivate all but vpe0 */ if (tc >= tclimit) { unsigned long tmp = read_vpe_c0_vpeconf0(); - + /*--------------------------------------------------------------------------------*\ + Virtual Processor Activated: If zero, no TCs bound to this VPE will + run. It is reset to 1 for VPE0, 0 for others. + \*--------------------------------------------------------------------------------*/ tmp &= ~VPECONF0_VPA; - - /* master VPE */ + /*--------------------------------------------------------------------------------*\ + Master Virtual Processor: If set, registers in different VPEs (or in the + TCs of different VPE affiliation) are made writable. It also controls + read/write access to MVPControl (see Section 7.2.2 “MVPControl + Register (CP0 Register 0, Select 1)”). It is reset to 1 for VPE0, 0 for + others. + \*--------------------------------------------------------------------------------*/ tmp |= VPECONF0_MVP; - write_vpe_c0_vpeconf0(tmp); + write_vpe_c0_vpeconf0(tmp); /*--- mbahr@avm: fix: auskommentiert sonst bleibt kernel haengen ---*/ } /* disable multi-threading with TC's */ @@ -1580,11 +2090,52 @@ write_tc_c0_tcstatus(tmp); } } +#else + { + unsigned int mvpconf0 = read_c0_mvpconf0(); + local_irq_save(flags); + mtflags = dmt(); + vpflags = dvpe(); + + /*--------------------------------------------------------------------------------*\ + Set to write to configuration register fields which are otherwise read- + only on conventional MIPS32® CPUs. Unset to make the fields in + the ConfigNN registers read-only. + \*--------------------------------------------------------------------------------*/ + set_c0_mvpcontrol(MVPCONTROL_VPC); + for (tc = 0; tc < hw_tcs; tc++) { + settc(tc); + + if(tc) { + t = alloc_tc(tc); + if (!t) { + err = -ENOMEM; + goto out; + } + if ((v = alloc_vpe(tc)) == NULL) { + printk(KERN_WARNING "VPE: unable to allocate VPE\n"); + + goto out_reenable; + } + v->ntcs = hw_tcs - tclimit; + /* add the tc to the list of this vpe's tc's. */ + list_add(&t->tc, &v->tc); + /* TC's */ + t->pvpe = v; /* set the parent vpe */ + } + smvp_tc_init(tc, mvpconf0); + smvp_vpe_init(tc, mvpconf0, hw_vpes); + } + } +#endif + dump_mtregs(); out_reenable: /* release config state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); - +#ifdef CONFIG_IFX_VPE_EXT + back_to_back_c0_hazard(); +#endif evpe(vpflags); emt(mtflags); local_irq_restore(flags);