uclinux内核中CPLB表项的生成

系统 1926 0

快乐虾

http://blog.csdn.net/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_tables dcplb_talbes ipdt_tables dpdt_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_LOCK CPLB_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

padding-right: 5.4pt; border-top: #ece9d8; padding-left: 5.4pt; padding-
分享到:
评论
xiaoer_1982
  • 浏览: 782189 次
  • 性别: Icon_minigender_2
  • 来自: 北京
最新评论

uclinux内核中CPLB表项的生成


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论