Hi team:
My customer found one MMU issue on MQX for vybrid, PLS check and confirm.
When they use Ethernet and SDHC driver together, for example FTP application, after running long period, they found SDHC card have 32bytes error data.
After disable L2 cache, the issue couldn't be reproduced.
they trace the code find that cache operation will call address translate function, _mmu_vtop, like below:
void _l2c310_cache_invalidate_line(void *addr)
{
/* addr parameter can be virtual address and this cache work only with physical address */
void *pa = NULL; /* physical address pointer */
if (_mmu_vtop(addr, &pa) == MQX_OK)
{
CA5L2C_reg7_inv_pa = (uint32_t)pa & (L2C_reg7_clean_pa_Index_MASK | L2C_reg7_clean_pa_Tag_MASK);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and EB, are emptyDrain the STB. Operation complete when all buffers, LRB, LFB, STB, and EB, are empty */
while (CA5L2C_reg7_cache_sync & L2C_reg7_cache_sync_C_MASK);
}
}
But this function _mmu_vtop do not prevent code reentry, the result will bring wrong PA address, which maybe write data to wrong address.
So whether need to add prevention code, like _mmu_lock(); to avoid this potential issue?
/*!
* \brief translate virtual address to physical address
*
* \param va
* \param pa
*
* \return MQX_OK or an error code
*/
_mqx_int _mmu_vtop(void *va, void **pa)
{
/* VA to PA translation with privileged read permission check */
MCR(15, 0, (uint32_t)va & 0xfffffc00, 7, 8, 0);
/* Read PA register */
MRC(15, 0, *(uint32_t*)pa, 7, 4, 0);
/* First bit of returned value is Result of conversion(0 is successful translation) */
if ((uint32_t)*pa & 0x01)
{
/* We can try write permission also */
/* VA to PA translation with privileged write permission check */
MCR(15, 0, (uint32_t)va & 0xfffffc00, 7, 8, 1);
/* Read PA register */
MRC(15, 0, *(uint32_t*)pa, 7, 4, 0);
/* First bit of returned value is Result of conversion(0 is successful translation) */
if ((uint32_t)*pa & 0x01)
{
return MQX_INVALID_POINTER;
}
}
/* complete address returning base + offset*/
*pa = (void *) (((uint32_t)*pa & 0xfffff000) | ((uint32_t)va & 0x00000fff));
return MQX_OK;
}
Hi,
After looking at your description it makes sense. But before contacting the experts I wonder if you can share some simple example we can use to reproduce the problem.
Best Regards,
Alejandro