uclinux内核中CPLB表项的生成

本文详细解析了ADSP-BF561双核处理器中CPLB表的生成过程,包括生成函数generate_cpl_tables及generate_cpltab_cpu的工作原理,并深入介绍了fill_cplbtab等关键函数的功能及其参数意义。

快乐虾

http://blog.youkuaiyun.com/lights_joy/

lights@hb165.com

 

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3 (smp patch, 移植到vdsp5)

Visual DSP++ 5.0(update 5)

 

欢迎转载但请保留作者信息

本文讨论链接:http://www.bfin-tools.org/bbs/viewthread.php?tid=23&extra=

 

cplb表的生成由generate_cpl_tables函数完成:

void __init generate_cpl_tables(void)

{

     unsigned int cpu;

 

     /* Generate per-CPU I&D CPLB tables */

     for (cpu = 0; cpu < NR_CPUS; ++cpu)

         generate_cpltab_cpu(cpu);

}

由于ab两个核都需要cpl表,因此实际工作将由generate_cpltab_cpu函数完成。它的主体结构如下:

void __init generate_cpltab_cpu(unsigned int cpu)

{

 

     u16 i, j, process;

     u32 a_start, a_end, as, ae, as_1m;

 

     struct cplb_tab *t_i = NULL;

     struct cplb_tab *t_d = NULL;

     struct s_cplb cplb;

 

     printk(KERN_INFO "NOMPU: setting up cplb tables for global access/n");

 

     cplb.init_i.size = CPLB_TBL_ENTRIES;

     cplb.init_d.size = CPLB_TBL_ENTRIES;

     cplb.switch_i.size = MAX_SWITCH_I_CPLBS;

     cplb.switch_d.size = MAX_SWITCH_D_CPLBS;

 

     cplb.init_i.pos = 0;

     cplb.init_d.pos = 0;

     cplb.switch_i.pos = 0;

     cplb.switch_d.pos = 0;

 

     cplb.init_i.tab = icplb_tables[cpu];

     cplb.init_d.tab = dcplb_tables[cpu];

     cplb.switch_i.tab = ipdt_tables[cpu];

     cplb.switch_d.tab = dpdt_tables[cpu];

…………………………

 

     for (i = ZERO_P; i < ARRAY_SIZE(cplb_data); ++i) {

         if (!cplb_data[i].valid)

              continue;

…………………………..

 

         for (j = INITIAL_T; j <= SWITCH_T; j++) {

 

              switch (j) {

              case INITIAL_T:

                   if (cplb_data[i].attr & INITIAL_T) {

                       t_i = &cplb.init_i;

                       t_d = &cplb.init_d;

                       process = 1;

                   } else

                       process = 0;

                   break;

              case SWITCH_T:

                   if (cplb_data[i].attr & SWITCH_T) {

                       t_i = &cplb.switch_i;

                       t_d = &cplb.switch_d;

                       process = 1;

                   } else

                       process = 0;

                   break;

              default:

                       process = 0;

                   break;

              }

 

              if (!process)

                   continue;

              if (cplb_data[i].attr & I_CPLB)

                   __fill_code_cplbtab(t_i, i, a_start, a_end);

 

              if (cplb_data[i].attr & D_CPLB)

                   __fill_data_cplbtab(t_d, i, a_start, a_end);

         }

     }

 

/* close tables */

 

     close_cplbtab(&cplb.init_i);

     close_cplbtab(&cplb.init_d);

 

     cplb.init_i.tab[cplb.init_i.pos] = -1;

     cplb.init_d.tab[cplb.init_d.pos] = -1;

     cplb.switch_i.tab[cplb.switch_i.pos] = -1;

     cplb.switch_d.tab[cplb.switch_d.pos] = -1;

 

}

整个流程挺简单的,用两重循环来配置icplb_tablesdcplb_talbesipdt_tablesdpdt_tables这四个全局的表。关键的表项生成由__fill_code_cplbtab__fill_data_cplbtab两个函数完成。

1.1    fill_cplbtab

这个是生成一个或者CPLB表项的最底层函数,__fill_code_cplbtab__fill_data_cplbtab均调用此函数来生成CPLB表项。其实现为:

static unsigned short __init

fill_cplbtab(struct cplb_tab *table,

          unsigned long start, unsigned long end,

          unsigned long block_size, unsigned long cplb_data)

{

     int i;

 

     switch (block_size) {

     case SIZE_4M:

         i = 3;

         break;

     case SIZE_1M:

         i = 2;

         break;

     case SIZE_4K:

         i = 1;

         break;

     case SIZE_1K:

     default:

         i = 0;

         break;

     }

 

     cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);

 

     while ((start < end) && (table->pos < table->size)) {

 

         table->tab[table->pos++] = start;

 

         if (lock_kernel_check(start, start + block_size) == IN_KERNEL)

              table->tab[table->pos++] =

                  cplb_data | CPLB_LOCK | CPLB_DIRTY;

         else

              table->tab[table->pos++] = cplb_data;

 

         start += block_size;

     }

     return 0;

}

static u16 __init lock_kernel_check(u32 start, u32 end)

{

     if ((end   <= (u32) _end && end   >= (u32)_stext) ||

         (start <= (u32) _end && start >= (u32)_stext))

         return IN_KERNEL;

     return 0;

}

也就是说,当这个区域中含有内核的代码或者数据时,将会自动加上CPLB_LOCKCPLB_DIRTY两个属性,即这个页将不允许进行切换。

 

1.2    __fill_code_cplbtab

这个函数将生成一个或者多个的icplb表项。其实现为:

/* helper function */

static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)

{

     if (cplb_data[i].psize) {

         fill_cplbtab(t,

                   cplb_data[i].start,

                   cplb_data[i].end,

                   cplb_data[i].psize,

                   cplb_data[i].i_conf);

     #if defined(CONFIG_BFIN_ICACHE)

         if (ANOMALY_05000263 && i == SDRAM_KERN) {

              fill_cplbtab(t,

                       cplb_data[i].start,

                       cplb_data[i].end,

                       SIZE_4M,

                       cplb_data[i].i_conf);

         } else

#endif

} else {

              fill_cplbtab(t,

                       cplb_data[i].start,

                       a_start,

                       SIZE_1M,

                       cplb_data[i].i_conf);

              fill_cplbtab(t,

                       a_start,

                       a_end,

                       SIZE_4M,

                       cplb_data[i].i_conf);

              fill_cplbtab(t, a_end,

                       cplb_data[i].end,

                       SIZE_1M,

                       cplb_data[i].i_conf);

         }

}

下图给出了初始化完成后的寄存器配置:

1.2.1   L1指令区域

     {

         .start = 0,   /* dyanmic */

         .end = 0, /* dynamic */

         .psize = SIZE_4M,

         .attr = INITIAL_T | SWITCH_T | I_CPLB,

         .i_conf = L1_IMEMORY,

         .d_conf = 0,

         .valid = 1,

         .name = "L1 I-Memory",

     },

这个块传递进来时,ICPLB_ADDR的值对于A核为0xffa0 0000,对于B核则为0xff60 0000。而ICPLB_DATA的值将为0x0003 0007,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

1

Locked, CPLB entry should not be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_LRUPRIO

8

0

Low importance

CPLB_MEM_LEV

9

0

无效

CPLB_L1_CHBL

12

0

Non cacheable in L1

PAGE_SIZE

17-16

11

4M Page size

 

1.2.2   内核区域

     {

         .start = 0,

         .end = 0,  /* dynamic */

         .psize = 0,

         .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,

         .i_conf = SDRAM_IGENERIC,

         .d_conf = SDRAM_DGENERIC,

         .valid = 1,

         .name = "Kernel Memory",

     },

这个块传递进来时,如果设置的内存大小为64M,它将连续创建15个入口项,其地址从0开始,按4M大小向上递增,且每个入口项的ICPLB_DATA的值都为0x0003 1205,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_LRUPRIO

8

0

Low importance

CPLB_MEM_LEV

9

1

Low priority

CPLB_L1_CHBL

12

1

Cacheable in L1

PAGE_SIZE

17-16

11

4M Page size

在保留1MDMA区域的情况下,还将创建三个额外的入口项,其地址为0x03c0 0000,以1M的大小向上递增,其ICPLB_DATA的值为0x0002 1205,除了PAGE_SIZE的大小为1M外,其余的与上表相同。

 

1.2.3   bootrom区域

     {

         .start = BOOT_ROM_START,

         .end = BOOT_ROM_START + BOOT_ROM_LENGTH,

         .psize = SIZE_1M,

         .attr = SWITCH_T | I_CPLB | D_CPLB,

         .i_conf = SDRAM_IGENERIC,

         .d_conf = SDRAM_DGENERIC,

         .valid = 1,

         .name = "On-Chip BootROM",

     },

这个块传递进来时,ICPLB_ADDR的值为0xef00 0000,入口项的ICPLB_DATA的值都为0x0002 1205,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_LRUPRIO

8

0

Low importance

CPLB_MEM_LEV

9

1

Low priority

CPLB_L1_CHBL

12

1

Cacheable in L1

PAGE_SIZE

17-16

10

1M Page size

 

1.3    __fill_data_cplbtab

这个函数用于填充一个或者多个DCPLB表项,其实现为:

static void __init

__fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)

{

     if (cplb_data[i].psize) {

         fill_cplbtab(t,

                   cplb_data[i].start,

                   cplb_data[i].end,

                   cplb_data[i].psize,

                   cplb_data[i].d_conf);

     } else {

         fill_cplbtab(t,

                   cplb_data[i].start,

                   a_start, SIZE_1M,

                   cplb_data[i].d_conf);

         fill_cplbtab(t, a_start,

                   a_end, SIZE_4M,

                   cplb_data[i].d_conf);

         fill_cplbtab(t, a_end,

                   cplb_data[i].end,

                   SIZE_1M,

                   cplb_data[i].d_conf);

     }

}

下图给出了初始化完成后的寄存器配置:

1.3.1   L1数据区域

     {

         .start = 0,   /* dynamic */

         .end = 0, /* dynamic */

         .psize = SIZE_4M,

         .attr = INITIAL_T | SWITCH_T | D_CPLB,

         .i_conf = 0,

         .d_conf = L1_DMEMORY,

#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))

         .valid = 1,

#else

         .valid = 0,

#endif

         .name = "L1 D-Memory",

     },

这个块传递进来时,DCPLB_ADDR的值对于A核为0xff80 0000,对于B核,它的值则为0xff40 0000。而DCPLB_DATA的值将为0x0003 009f,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

1

Locked, CPLB entry should not be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

无效

CPLB_L1_CHBL

12

0

Non cacheable in L1

CPLB_WT

14

0

Write back

CPLB_L1_AOW

15

0

无效

PAGE_SIZE

17-16

11

4M Page size

 

1.3.2   L2缓存区域

     {

#if defined(CONFIG_BF561) || defined(CONFIG_BF54x)

         .start = L2_START,

         .end = L2_START+L2_LENGTH,

         .psize = SIZE_1M,

         .attr = L2_ATTR,

         .i_conf = L2_MEMORY,

         .d_conf = L2_MEMORY,

         .valid = 1,

#else

         .valid = 0,

#endif

         .name = "L2 Memory",

     },

这个块传递进来时,DCPLB_ADDR的值为0xfeb0 0000,而DCPLB_DATA的值将为0x0002 009f,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

1

Locked, CPLB entry should not be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

无效

CPLB_L1_CHBL

12

0

Non cacheable in L1

CPLB_WT

14

0

Write back

CPLB_L1_AOW

15

0

无效

PAGE_SIZE

17-16

10

1M Page size

 

1.3.3   内核区域

     {

         .start = 0,

         .end = 0,  /* dynamic */

         .psize = 0,

         .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,

         .i_conf = SDRAM_IGENERIC,

         .d_conf = SDRAM_DGENERIC,

         .valid = 1,

         .name = "Kernel Memory",

     },

这个块传递进来时,如果设置的内存大小为64M,它将连续创建15个入口项,其地址从0开始,按4M大小向上递增,且每个入口项的DCPLB_DATA的值都为0x0003 d09d,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

High priority

CPLB_L1_CHBL

12

1

Cacheable in L1

CPLB_WT

14

1

Write through

CPLB_L1_AOW

15

1

Allow cache lines on reads and writes

PAGE_SIZE

17-16

11

4M Page size

在保留1MDMA区域的情况下,还将创建三个额外的入口项,其地址为0x03c0 0000,以1M的大小向上递增,其DCPLB_DATA的值为0x0002 d09d,除了PAGE_SIZE的大小为1M外,其余的与上表相同。

 

1.3.4   保留的DMA区域

     {

         .start = 0, /* dynamic */

         .end = 0,   /* dynamic */

         .psize = SIZE_1M,

         .attr = INITIAL_T | SWITCH_T | D_CPLB,

         .d_conf = SDRAM_DNON_CHBL,

         .valid = 1,

         .name = "Uncached DMA Zone",

     },

这个块传递进来时,对于64MSDRAMDCPLB_ADDR的值为0x03f0 0000,而DCPLB_DATA的值将为0x0002 009d,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

无效

CPLB_L1_CHBL

12

0

Non cacheable in L1

CPLB_WT

14

0

Write back

CPLB_L1_AOW

15

0

无效

PAGE_SIZE

17-16

10

1M Page size

可以看出,它的配置与L2一样,只是可以Unlock而已。

 

1.3.5   ASYNC_MEM

     {

         .start = ASYNC_BANK0_BASE,

         .end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,

         .psize = 0,

         .attr = SWITCH_T | D_CPLB,

         .d_conf = SDRAM_EBIU,

         .valid = 1,

         .name = "Asynchronous Memory Banks",

     },

这个块传递进来时,它将连续创建64个入口项,其地址从0x2000 0000开始,按4M大小向上递增,且每个入口项的DCPLB_DATA的值都为0x0003 009d,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

无效

CPLB_L1_CHBL

12

0

Non cacheable in L1

CPLB_WT

14

0

Write back

CPLB_L1_AOW

15

0

无效

PAGE_SIZE

17-16

11

4M Page size

 

1.3.6   Boot rom区域

          {

         .start = BOOT_ROM_START,

         .end = BOOT_ROM_START + BOOT_ROM_LENGTH,

          .psize = SIZE_1M,

         .attr = SWITCH_T | I_CPLB | D_CPLB,

         .i_conf = SDRAM_IGENERIC,

         .d_conf = SDRAM_DGENERIC,

         .valid = 1,

         .name = "On-Chip BootROM",

     },

这个块传递进来时,DCPLB_ADDR的值为0xef00 0000,而DCPLB_DATA的值将为0x0002 d09d,这个值的意义是:

数据位

意义

CPLB_VALID

0

1

Valid(enabled) CPLB entry

CPLB_LOCK

1

0

Unlocked, CPLB entry can be replaced

CPLB_USER_RD

2

1

User mode read access permitted

CPLB_USER_WR

3

1

User mode write access permitted

CPLB_SUPV_WR

4

1

Supervisor mode write access permitted

CPLB_DIRTY

7

1

无效

CPLB_MEM_LEV

9

0

High priority

CPLB_L1_CHBL

12

1

Cacheable in L1

CPLB_WT

14

1

Write through

CPLB_L1_AOW

15

1

Allow cache lines on reads and writes

PAGE_SIZE

17-16

10

1M Page size

 

 

1       参考资料

uclinux-2008r1(bf561)内核存储区域初探(2008/6/4)

cplb_data全局变量看uclinux的存储空间划分(2009-02-04)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值