快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
ADSP-BF561
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-
发表评论
最新评论
|
评论