Tuesday, February 27, 2007

Blackfin CPLB - 1

ata Structure:
======================

mach/bf537.h
-----------------
#define MAX_CPLBS (16 * 2)

/*
* Number of required data CPLB switchtable entries
* MEMSIZE / 4 (we mostly install 4M page size CPLBs
* approx 16 for smaller 1MB page size CPLBs for allignment purposes
* 1 for L1 Data Memory
* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
* 1 for ASYNC Memory
*/

#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) *
2)

/*
* Number of required instruction CPLB switchtable entries
* MEMSIZE / 4 (we mostly install 4M page size CPLBs
* approx 12 for smaller 1MB page size CPLBs for allignment purposes
* 1 for L1 Instruction Memory
* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
*/

#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)

include/asm/cplbinit.h
----------------------

enum
{ZERO_P, L1I_MEM, L1D_MEM, SDRAM_KERN , SDRAM_RAM_MTD, SDRAM_DMAZ,
RES_MEM, ASYNC_MEM, L2_MEM};

struct cplb_desc {
u32 start; /* start address */
u32 end; /* end address */
u32 psize; /* prefered size if any otherwise 1MB or 4MB*/
u16 attr;/* attributes */
u16 i_conf;/* I-CPLB DATA */
u16 d_conf;/* D-CPLB DATA */
u16 valid;/* valid */
const s8 name[30];/* name */
};

struct cplb_tab {
u_long *tab;
u16 pos;
u16 size;
};

u_long icplb_table[MAX_CPLBS+1];
u_long dcplb_table[MAX_CPLBS+1];

/* Till here we are discussing about the static memory management
model.
* However, the operating envoronments commonly define more CPLB
* descriptors to cover the entire addressable memory than will fit into
* the available on-chip 16 CPLB MMRs. When this happens, the below
table
* will be used which will hold all the potentially required CPLB
descriptors
*
* This is how Page descriptor Table is implemented in uClinux/Blackfin.
*/

u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];

#ifdef CONFIG_CPLB_INFO
u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
#==endif

struct s_cplb {
struct cplb_tab init_i;
struct cplb_tab init_d;
struct cplb_tab switch_i;
struct cplb_tab switch_d;
};

static struct cplb_desc cplb_data[] = {
{
.start = 0,
.end = SIZE_4K,
.psize = SIZE_4K,
.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
.i_conf = SDRAM_OOPS,
.d_conf = SDRAM_OOPS,
#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
.valid = 1,
#else
.valid = 0,
#==endif
.name = "ZERO Pointer Saveguard",
},
{
.start = L1_CODE_START,
.end = L1_CODE_START + L1_CODE_LENGTH,
.psize = SIZE_4M,
.attr = INITIAL_T | SWITCH_T | I_CPLB,
.i_conf = L1_IMEMORY,
.d_conf = 0,
.valid = 1,
.name = "L1 I-Memory",
},
{
.start = L1_DATA_A_START,
.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
.psize = SIZE_4M,
.attr = INITIAL_T | SWITCH_T | D_CPLB,
.i_conf = 0,
.d_conf = L1_DMEMORY,
.valid = 1,
.name = "L1 D-Memory",
},
{
.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 = "SDRAM Kernel",
},
{
.start = 0, /* dynamic */
.end = 0, /* dynamic */
.psize = 0,
.attr = INITIAL_T | SWITCH_T | D_CPLB,
.i_conf = SDRAM_IGENERIC,
.d_conf = SDRAM_DNON_CHBL,
.valid = 1,
.name = "SDRAM RAM MTD",
},
{
.start = 0, /* dynamic */
.end = 0, /* dynamic */
.psize = SIZE_1M,
.attr = INITIAL_T | SWITCH_T | D_CPLB,
.d_conf = SDRAM_DNON_CHBL,
.valid = 1,//(DMA_UNCACHED_REGION > 0),
.name = "SDRAM Uncached DMA ZONE",
},
{
.start = 0, /* dynamic */
.end = 0, /* dynamic */
.psize = 0,
.attr = SWITCH_T | D_CPLB,
.i_conf = 0, /* dynamic */
.d_conf = 0, /* dynamic */
.valid = 1,
.name = "SDRAM Reserved Memory",
},
{
.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 = "ASYNC Memory",
},
{
#if defined(CONFIG_BF561)
.start = L2_SRAM,
.end = L2_SRAM_END,
.psize = SIZE_1M,
.attr = SWITCH_T | D_CPLB,
.i_conf = L2_MEMORY,
.d_conf = L2_MEMORY,
.valid = 1,
#else
.valid = 0,
#==endif
.name = "L2 Memory",
}
};

Operation:

Initialize:
===============

arch/blackfin/kernel/setup.c:
------------------------------
/* Initilize bellow tables using definition in cplb_data[]

u_long icplb_table[MAX_CPLBS+1];
u_long dcplb_table[MAX_CPLBS+1];

u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];

*/

static unsigned short __init
fill_cplbtab(struct cplb_tab *table,
unsigned long start, unsigned long end,
unsigned long block_size, unsigned long cplb_data)
{
}

static unsigned short __init
close_cplbtab(struct cplb_tab *table)
{
}

static void __init generate_cpl_tables(void)
{

}

mach-common/cacheinit.S:
-------------------------

/* Copy icplb_table[], dcplb_table[] to CPLB MMRs */

Note that when the Cache is disabled, the CPLB MMRs will not be filled.

#if defined(CONFIG_BLKFIN_CACHE)
ENTRY(_bfin_icache_init)

/* Initialize Instruction CPLBS */

I0.L = (ICPLB_ADDR0 & 0xFFFF);
I0.H = (ICPLB_ADDR0 >> 16);

I1.L = (ICPLB_DATA0 & 0xFFFF);
I1.H = (ICPLB_DATA0 >> 16);

I2.L = _icplb_table;
I2.H = _icplb_table;

r1 = -1; /* end point comparison */
r3 = 15; /* max counter */

/* read entries from table */

.Lread_iaddr:
R0 = [I2++];
CC = R0 == R1;
IF CC JUMP .Lidone;
[I0++] = R0;

.Lread_idata:
R2 = [I2++];
[I1++] = R2;
R3 = R3 + R1;
CC = R3 == R1;
IF !CC JUMP .Lread_iaddr;

.Lidone:
/* Enable Instruction Cache */
P0.l = (IMEM_CONTROL & 0xFFFF);
P0.h = (IMEM_CONTROL >> 16);
R1 = [P0];
R0 = (IMC | ENICPLB);
R0 = R0 | R1;

/* Anomaly 05000125 */
CLI R2;
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
.align 8;
[P0] = R0;
SSYNC;
STI R2;
RTS;
#==endif

#if defined(CONFIG_BLKFIN_DCACHE)
ENTRY(_bfin_dcache_init)

/* Initialize Data CPLBS */

I0.L = (DCPLB_ADDR0 & 0xFFFF);
I0.H = (DCPLB_ADDR0 >> 16);

I1.L = (DCPLB_DATA0 & 0xFFFF);
I1.H = (DCPLB_DATA0 >> 16);

I2.L = _dcplb_table;
I2.H = _dcplb_table;

R1 = -1; /* end point comparison */
R3 = 15; /* max counter */

/* read entries from table */
.Lread_daddr:
R0 = [I2++];
cc = R0 == R1;
IF CC JUMP .Lddone;
[I0++] = R0;

.Lread_ddata:
R2 = [I2++];
[I1++] = R2;
R3 = R3 + R1;
CC = R3 == R1;
IF !CC JUMP .Lread_daddr;
.Lddone:
P0.L = (DMEM_CONTROL & 0xFFFF);
P0.H = (DMEM_CONTROL >> 16);
R1 = [P0];

R0 = DMEM_CNTR;

R0 = R0 | R1;
/* Anomaly 05000125 */
CLI R2;
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
.align 8;
[P0] = R0;
SSYNC;
STI R2;
RTS;
#==endif

Replacement:
================

Exception -> entry(trap)->extable:

mach-common/entry.S
--------------------

ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor
mode)*/
/* Since the kernel stack can be anywhere, it's not guaranteed
to be
* covered by a CPLB. Switch to an exception stack; use RETN as
a
* scratch register (for want of a better option).
*/
retn = sp;
sp.l = _exception_stack_top;
sp.h = _exception_stack_top;
/* Try to deal with syscalls quickly. */
[--sp] = ASTAT;
[--sp] = (R7:6, P5:4);
DEBUG_STOP_HWTRACE
r7 = SEQSTAT; /* reason code is in bit 5:0 */
r6.l = lo(SEQSTAT_EXCAUSE);
r6.h = hi(SEQSTAT_EXCAUSE);
r7 = r7 & r6;
p5.h = _extable;
p5.l = _extable;
p4 = r7;
p5 = p5 + (p4 << 2);
p4 = [p5];
jump (p4);

mach_common/entry.S:
--------------------
extable: (64 entry - corresponds to SEQSTAT[EXCAUSE] (0-5))

/*
* Put these in the kernel data section - that should always be covered
by
* a CPLB. This is needed to ensure we don't get double fault conditions
*/

.data
ALIGN
_extable:
/* entry for each EXCAUSE[5:0]
* This table bmust be in sync with the table
in ./kernel/traps.c
* EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16
to be user defined
*/
/-------------------
The Force Exception instruction forces an exception with code uimm4.
When the EXCPT instruction is issued, the sequencer vectors to the
exception handler that the user provides.
Application-level code uses the Force Exception instruction for
operating system calls. The instruction does not set the EVSW bit (bit
3) of the ILAT register.
--------------------/

.long _ex_syscall; /* 0x00 - User Defined - Linux Syscall
*/
.long _ex_soft_bp /* 0x01 - User Defined - Software
breakpoint */
.long _ex_trap_c /* 0x02 - User Defined */
.long _ex_trap_c /* 0x03 - User Defined - Atomic test
and set service */
.long _ex_spinlock /* 0x04 - User Defined */
.long _ex_trap_c /* 0x05 - User Defined */
.long _ex_trap_c /* 0x06 - User Defined */
.long _ex_trap_c /* 0x07 - User Defined */
.long _ex_trap_c /* 0x08 - User Defined */
.long _ex_trap_c /* 0x09 - User Defined */
.long _ex_trap_c /* 0x0A - User Defined */
.long _ex_trap_c /* 0x0B - User Defined */
.long _ex_trap_c /* 0x0C - User Defined */
.long _ex_trap_c /* 0x0D - User Defined */
.long _ex_trap_c /* 0x0E - User Defined */
.long _ex_trap_c /* 0x0F - User Defined */
.long _ex_single_step /* 0x10 - HW Single step */
.long _ex_trap_c /* 0x11 - Trace Buffer Full */
.long _ex_trap_c /* 0x12 - Reserved */
.long _ex_trap_c /* 0x20 - Reserved */
<snip>
.long _ex_trap_c /* 0x21 - Undefined Instruction */
.long _ex_trap_c /* 0x22 - Illegal Instruction
Combination */
.long _ex_dcplb /* 0x23 - Data CPLB Protection Violation
*/
.long _ex_trap_c /* 0x24 - Data access misaligned */
.long _ex_trap_c /* 0x25 - Unrecoverable Event */
.long _ex_dcplb /* 0x26 - Data CPLB Miss */
.long _ex_trap_c /* 0x27 - Data CPLB Multiple Hits -
Linux Trap Zero */
.long _ex_trap_c /* 0x28 - Emulation Watchpoint */
.long _ex_trap_c /* 0x29 - Instruction fetch access error
(535 only) */
.long _ex_trap_c /* 0x2A - Instruction fetch misaligned
*/
.long _ex_icplb /* 0x2B - Instruction CPLB protection
Violation */
.long _ex_icplb /* 0x2C - Instruction CPLB miss */
.long _ex_trap_c /* 0x2D - Instruction CPLB Multiple Hits
*/
.long _ex_trap_c /* 0x2E - Illegal use of Supervisor
Resource */
.long _ex_trap_c /* 0x2E - Illegal use of Supervisor
Resource */
<snip>

/* Slightly simplified and streamlined entry point for CPLB misses.
* This one does not lower the level to IRQ5, and thus can be used to
* patch up CPLB misses on the kernel stack.
*/
ENTRY(_ex_dcplb)
/*
* Work around an anomaly: if we see a new DCPLB fault, return
* without doing anything. Then, if we get the same fault
again,
* handle it.
*/
p5.l = _last_cplb_fault_retx;
p5.h = _last_cplb_fault_retx;
r7 = [p5];
r6 = retx;
[p5] = r6;
cc = r6 == r7;
if !cc jump _return_from_exception;
/* fall through */
/-------------------------
/* Used by the assembly entry point to work around an anomaly. */
_last_cplb_fault_retx:
.long 0;
--------------------------/

ENTRY(_ex_icplb)
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
SAVE_ALL_SYS
call __cplb_hdr;
DEBUG_START_HWTRACE
RESTORE_ALL_SYS
SP = RETN;
rtx;

ENTRY(_handle_bad_cplb)
/* To get here, we just tried and failed to change a CPLB
* so, handle things in trap_c (C code), by lowering to
* IRQ5, just like we normally do. Since this is not a
* "normal" return path, we have a do alot of stuff to
* the stack to get ready so, we can fall through - we
* need to make a CPLB exception look like a normal exception
*/

DEBUG_START_HWTRACE
RESTORE_ALL_SYS
[--sp] = ASTAT;
[--sp] = (R7:6, P5:4);

ENTRY(_ex_trap_c)
/* Call C code (trap_c) to handle the exception, which most
* likely involves sending a signal to the current process.
* To avoid double faults, lower our priority to IRQ5 first.
*/
P5.h = _exception_to_level5;
P5.l = _exception_to_level5;
p4.l = lo(EVT5);
p4.h = hi(EVT5);
[p4] = p5;
csync;

/* Disable all interrupts, but make sure level 5 is enabled so
* we can switch to that level. Save the old mask. */
cli r6;
p4.l = _excpt_saved_imask;
p4.h = _excpt_saved_imask;
[p4] = r6;
r6 = 0x3f;
sti r6;

/* Save the excause into a circular buffer, in case the
instruction
* which caused this excecptions causes others.
*/
P5.l = _in_ptr_excause;
P5.h = _in_ptr_excause;
R7 = [P5];
R7 += 4;
R6 = 0xF;
R7 = R7 & R6;
[P5] = R7;
R6.l = _excause_circ_buf;
R6.h = _excause_circ_buf;
R7 = R7 + R6;
p5 = R7;
R6 = SEQSTAT;
[P5] = R6;

DEBUG_START_HWTRACE
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
SP = RETN;
raise 5;
rtx;

mach-common/cplbhdlr.S
---------------------------

.text

.type _cplb_mgr, STT_FUNC;
.type _panic_cplb_error, STT_FUNC;

.align 2

.global __cplb_hdr;
.type __cplb_hdr, STT_FUNC;
ENTRY(__cplb_hdr)
R2 = SEQSTAT;

/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
R2 <<= 26;
R2 >>= 26;

R1 = 0x23; /* Data access CPLB protection violation */
CC = R2 == R1;
IF !CC JUMP .Lnot_data_write;
R0 = 2; /* is a write to data space*/
JUMP .Lis_icplb_miss;

.Lnot_data_write:
R1 = 0x2C; /* CPLB miss on an instruction fetch */
CC = R2 == R1;
R0 = 0; /* is_data_miss == False*/
IF CC JUMP .Lis_icplb_miss;

R1 = 0x26;
CC = R2 == R1;
IF !CC JUMP .Lunknown;

R0 = 1; /* is_data_miss == True*/

.Lis_icplb_miss:

#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE)
# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE)
R1 = CPLB_ENABLE_ICACHE;
# endif
# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
R1 = CPLB_ENABLE_DCACHE;
# endif
# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
# endif
#else
R1 = 0;

1 comment:

superqq3000 said...

hello! A Good News,google introduce a very user-friendly browser,Free download Quickly,Please visit my blog thank you

Blog Archive