Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

DSP MMU Faults

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

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

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

[0x01] Unrecoverable TLB Miss

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

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:

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"
},
];

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

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:

#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);
    }
}

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

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:

  1. 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.