mips Shadow register

来源:互联网 发布:网络布线人工费 编辑:程序博客网 时间:2024/05/18 21:49

对mips32_r2和mips64_r2而言,有shadow register可用来加快mips中断处理。shadow register数目在芯片设计时是可配置的。

在/proc/cpuinfo中保存有系统的相关信息(cat /proc/cpuinfo)。

如果shadow register sets    : 2,标明有2套GPRs。

这个shadow register sets的值对应cpu_data[n].srsets值,而cpu_data[n].srsets值由cp0的srsctl寄存器的bit[29:26]决定:

arch\mips\kernel\cpu-probe.c
       if (cpu_has_mips_r2)
              c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;

 

利用shadow register可适当加快mips中断处理,但是:

1. 使用shadow register加速中断处理能力有限,主要是节省保存和恢复GPRs的时间,约几十个cycle,

2. 允许中断嵌套时需要仔细考虑,在嵌套中断处理中需要保存GPRs,并考虑srsctl寄存器的保存。

关于如何使用shadow register: 

《Programming the MIPS32 24KE core family》

How new shadow sets get selected on an interrupt

In EIC mode, the external interrupt controller proposes a shadow register set number with each requested interrupt (nonzero IPL). When the CPU takes an interrupt, the externally-supplied set number determines the next set and is made visible in SRSCtl[EICSS] until the next interrupt.

In VI mode (no external interrupt controller) the core sees only eight possible interrupt numbers; the SRSMap register contains eight 4-bit fields, defining the register set to use for each of the eight interrupt levels, as shown in Figure 5.4.

Figure 5.4 Fields in the SRSMap Register

In SRSMap, each of the SSV7-0 fields has the shadow set number to be used when handling the interrupt for the corresponding Cause[IP7-0] bit. A zero shadow set number means not to use a shadow set. A number than the highest valid set (as found in SRSCtl[HSS]) has unpredictable results: don’t do that.

If you are remaining with “classic” interrupt mode, it’s still possible to use one shadow set for all exception handlers - including interrupt handlers - by setting SRSCtl[ESS] non-zero.

In “EIC” interrupt mode, this register has no effect and the shadow set number to be used is determined by an input bus from the interrupt controller.

 

Software support for shadow registers

Shadow registers work “as if by magic” for short interrupt routines which run entirely in exception mode (that is, with Status[EXL] set). The shadow registers are not just efficient because there’s no need to save user registers; the shadow registers can also be used to hold contextual information for one or more interrupt routines which uses a particular shadow set. For more ambitious interrupt nesting schemes, software must save and stack copies of SRSCtl[PSS] alongside its copies of EPC; and it’s entirely up to the software to determine when an interrupt handler can just go ahead and use a register set, and when it needs to save values on entry and restore them on exit. That’s at least as difficult as it sounds: shadow sets are probably best used purely for very low-level, high-speed handlers.

 

 

下面列一下linux中读取芯片(以74k为例)信息的一些函数:

对74k而言process ID是cpu_probe processor_id is 0x00019750

__cpuinit void cpu_probe(void)

{

...

       c->processor_id = read_c0_prid();

       switch (c->processor_id & 0xff0000) {

...

       case PRID_COMP_MIPS:

              cpu_probe_mips(c, cpu);

              break;

...

       }

...

}

cpu_probe_mips函数:

static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)

{

       decode_configs(c);

       switch (c->processor_id & 0xff00) {

       case PRID_IMP_74K:

              c->cputype = CPU_74K;

              __cpu_name[cpu] = "MIPS 74Kc";

              break;

       }

 

       spram_config();

}

decode_configs函数

static void __cpuinit decode_configs(struct cpuinfo_mips *c)

{

       int ok;

 

       /* MIPS32 or MIPS64 compliant CPU.  */

       c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |

                    MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;

 

       c->scache.flags = MIPS_CACHE_NOT_PRESENT;

 

       ok = decode_config0(c);                     /* Read Config registers.  */

       BUG_ON(!ok);                           /* Arch spec violation!  */

       if (ok)

              ok = decode_config1(c);

       if (ok)

              ok = decode_config2(c);

       if (ok)

              ok = decode_config3(c);

       if (ok)

              ok = decode_config4(c);

 

       mips_probe_watch_registers(c);

}

函数decode_config0见下面,由于74k的config寄存器的值为:

static inline unsigned int decode_config0(struct cpuinfo_mips *c)

{

       unsigned int config0;

       int isa;

 

       config0 = read_c0_config();

 

       if (((config0 & MIPS_CONF_MT) >> 7) == 1)

              c->options |= MIPS_CPU_TLB;

       isa = (config0 & MIPS_CONF_AT) >> 13;

       switch (isa) {

       case 0:

              switch ((config0 & MIPS_CONF_AR) >> 10) {

              case 0:

                     c->isa_level = MIPS_CPU_ISA_M32R1;

                     break;

              case 1:

                     c->isa_level = MIPS_CPU_ISA_M32R2;

                     break;

              default:

                     goto unknown;

              }

              break;

 

(config0 & MIPS_CONF_AT) >> 13(isa) = 0

((config0 & MIPS_CONF_AR) >> 10) = 1

所以c->isa_level = MIPS_CPU_ISA_M32R2

 

在arch\mips\kernel\cpu-probe.c里

       if (cpu_has_mips_r2)

              c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;

       else

              c->srsets = 1;

 

在arch/mips/include/asm/cpu-featues.h中:

#define cpu_has_mips32       (cpu_has_mips32r1 | cpu_has_mips32r2)

#define cpu_has_mips64       (cpu_has_mips64r1 | cpu_has_mips64r2)

#define cpu_has_mips_r1      (cpu_has_mips32r1 | cpu_has_mips64r1)

#define cpu_has_mips_r2      (cpu_has_mips32r2 | cpu_has_mips64r2)

#define cpu_has_mips_r (cpu_has_mips32r1 | cpu_has_mips32r2 | \

                      cpu_has_mips64r1 | cpu_has_mips64r2)

 

# ifndef cpu_has_mips32r1

# define cpu_has_mips32r1   (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R1)

# endif

# ifndef cpu_has_mips32r2

# define cpu_has_mips32r2   (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R2)

# endif

# ifndef cpu_has_mips64r1

# define cpu_has_mips64r1   (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R1)

# endif

# ifndef cpu_has_mips64r2

# define cpu_has_mips64r2   (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R2)

# endif

 

在arch/mips/kernel/proc.c中show_cpuinfo函数中有打印shadow register的数目

       seq_printf(m, "shadow register sets\t: %d\n",

                     cpu_data[n].srsets);

cat /proc/cpuinfo即可看到。