NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
DSP MMU Faults
Contents
Introduction[edit]
Some TI processors such as the OMAP3530 have a memory management unit (MMU) for both the ARM and the DSP. When running a Codec Engine application on these processors it's possible that you might see errors related to the DSP MMU. The purpose of this page is to give you some insight into what is responsible for those errors.
Error Messages[edit]
The resulting message will look something like this:
DSP MMU Error Fault! MMU_IRQSTATUS = [0x10]. Virtual DSP addr reference that generated the interrupt = [0x82f00000].
There are two key pieces of information in that message, MMU_IRQSTATUS and the virtual address that generated that interrupt.
The MMU_IRQSTATUS register for OMAP3530 is described in document spruff5. Consulting that document gives the following info related to the MMU_IRQSTATUS register:
Error Code | Error Name | Description |
---|---|---|
0x01 | TLB MISS | Unrecoverable TLB miss (hardware TWL disabled) |
0x02 | TRANSLATION FAULT | Invalid descriptor in translation tables (translation fault) |
0x04 | EMU MISS | Unrecoverable TLB miss during debug (hardware TWL disabled) |
0x08 | TABLE WALK FAULT | Error response received during a table walk |
0x10 | MULTI HIT FAULT | Error caused by multiple matches in the TLB |
Common Issues[edit]
[0x01] Unrecoverable TLB Miss[edit]
Perhaps the most common issue is an "unrecoverable TLB miss". In this scenario the DSP is trying to access an address that has not been mapped into the MMU. This could potentially be due to code that has crashed and is accessing memory addresses that it's not allowed to access.
Another common issue would be if the DSP is trying to access a data buffer that has not been mapped into the MMU. External memory allocated by the CMEM module (in its first block) is automatically mapped when using Codec Engine. However, it is possible that one may wish for the DSP to access memory that is not allocated by the CMEM module (e.g. buffers allocated by device drivers, buffers allocated from the 2nd CMEM block, etc.). When this memory is not mapped, the DSP MMU fault error message for "Unrecoverable TLB miss" described in Error Messages will appear, and the DSP will not be able to access the buffer.
Note however that there are only 31 entries for mapping buffers so you should try to aggregate all such memory sections into one large buffer. There are different ways to map such a buffer. This section attempts to give some suggestions.
If you know the memory range to map to the DSP MMU at build time of DSP server[edit]
In Codec Engine 2.x (starting with 2.20), you can simply add a definition for the memory range in the DSP server's DSP/BIOS (.tcf) configuration file. For example:
<syntaxhighlight lang='javascript'> var mem_ext = [ ... {
comment: "Mapping this memory region to DSP MMU", name: "MYMEM", base: 0x85800000, // Base physical address of memory region len: 0x00400000, // Length of memory region to be mapped space: "data"
}, ]; </syntaxhighlight>
This would allow the DSP to see this memory region during execution, as createFromServer() would automatically take note of it and pass it to DSPLINK which does the mapping during initialization.
If you know the memory range to be mapped only at runtime[edit]
In DSP Link 1.x (starting with 1.60), you can map a memory region to the DSP MMU during application runtime. In this case, include the following functions to your application:
<syntaxhighlight lang='c'>
- include <dsplink.h>
- include <proc.h>
- include <procdefs.h>
- define ID_PROCESSOR 0
/* Map area starting at 'dspAddr' (physical address on DSP) with a length of 'size' bytes */ Bool mapToDspMMU(Int8 * dspAddr, Int size) {
DSP_STATUS status; ProcMemMapInfo mapInfo;
mapInfo.dspAddr = (Uint32)dspAddr; mapInfo.size = size;
status = PROC_control(ID_PROCESSOR, PROC_CTRL_CMD_MMU_ADD_ENTRY, &mapInfo);
if (DSP_SUCCEEDED(status)) { return (TRUE); } else { return (FALSE); }
}
/* Unmap area starting at 'dspAddr' (physical address on DSP) with a length of 'size' bytes */ Bool unmapFromDspMMU(Int8 * dspAddr, Int size) {
DSP_STATUS status; ProcMemMapInfo mapInfo;
mapInfo.dspAddr = (Uint32)dspAddr; mapInfo.size = size;
status = PROC_control(ID_PROCESSOR, PROC_CTRL_CMD_MMU_DEL_ENTRY, &mapInfo);
if (DSP_SUCCEEDED(status)) { return (TRUE); } else { return (FALSE); }
} </syntaxhighlight>
Note that to compile these functions, you need to have DSPLINK include paths and #defines setup during compiler invocation. See DSPLINK documentation for details on how to find out this information.
You can then use these functions in your application to map/unmap a memory region. Be aware of the fact that up to 31 TLBs are available for memory mapping on the DSP and you will get errors if you exceed this number. See LNK 181 DES in DSPLINK documentation for details.
This topic has good information on optimizing the number of TLB entries used in general.
[0x10] Multi hit fault[edit]
An easy issue to run into is the "multi hit fault" (MMU_IRQSTATUS = 0x10). This means that the same address is present multiple times in the TLB. In other words, the memory map sections are overlapping. There's an easy method to figure this out if you're using Codec Engine. First, invoke your application with CE_DEBUG=2:
- CE_DEBUG=2 ./app.out
Codec Engine will print out additional debug info which shows your memory map configuration. Here's the relevant piece:
@1,301,101us: [+2 T:0x4096e490] OP - Processor_create_d> Initializing DSP PROC... @1,301,169us: [+2 T:0x4096e490] OP - Processor_create_d> Using DspLink config data for entry #0 [server 'video_copy.x64P'] @1,301,285us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #0 to Link configuration: name='DDR2', startAddress=0x82c00000, sizeInBytes=0x300000, shared=1 @1,301,389us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #1 to Link configuration: name='DSPLINKMEM', startAddress=0x82f01000, sizeInBytes=0xff000, shared=1 @1,301,481us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #2 to Link configuration: name='RESET_VECTOR', startAddress=0x82f00000, sizeInBytes=0x1000, shared=1 @1,301,570us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #3 to Link configuration: name='L4PER', startAddress=0x49000000, sizeInBytes=0x800000, shared=0 @1,635,383us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #4 to Link configuration: name='DDRALGHEAP', startAddress=0x83000000, sizeInBytes=0x1000000, shared=0 @1,635,511us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #5 to Link configuration: name='L4CORE', startAddress=0x48000000, sizeInBytes=0x1000000, shared=0 @1,635,608us: [+2 T:0x4096e490] OP - Processor_create_d> Found 'CMEM' entry, adjusting base and size according to CMEM_getBlock() @1,635,693us: [+0 T:0x4096e490] OP - Processor_create_d> Setting CMEM base to 0x82000000, size to 0x1000000 @1,635,769us: [+2 T:0x4096e490] OP - Processor_create_d> Adding DSP segment #6 to Link configuration: name='CMEM', startAddress=0x82000000, sizeInBytes=0x1000000, shared=0
So in this example above you can see that CMEM occupies the address range 0x82000000 - 0x83000000. However, this overlaps several other sections! So in this example by changing the size of CMEM (i.e. at the time of the insmod) we could successfully resolve the issue.