现在的位置: 首页 > 综合 > 正文

为什么在44B0操作RTL8019时必须关闭cache呢?

2013年05月10日 ⁄ 综合 ⁄ 共 1515字 ⁄ 字号 评论关闭

       最近花了好长一段时间调试44B0板子上的RTL8019网卡驱动,在原来的uboot的驱动中由于参数设置不正确,甚至连数据包都无法发送出来。我将一个在ADS1.2工程中好用的代码移植到uboot内,将原来的8bit模式更改为16bit模式,并对内存控制器的设置也做了相应的修改。本以为这种移植工作应该是比较容易调通的,可是实际调试中却发现,发送数据没有问题了,但是在接收数据时读到的数据长度总是错误的。再仔细追踪调试时,甚至发现设置到MAC地址寄存器的地址也会发生变化,我在程序里初始化阶段设置了一个MAC地址,然后立即读出,发现读出数值与设置值是一样的。在每次发送数据前和接受数据前也都读取一次MAC地址,发现只有第一次发送时读出的数值与最初的设置值是一样的,后面再次发送和接收时读取的数值都是错误的。这个问题困扰了我好久,最初时我还以为是memory controller的设置有问题呢,可是在初始化阶段时能够正确读出RTL8019的芯片ID的,而且对于某个寄存器,如果在写入后立即读出那么其数值也是正确的,因此可以肯定memory controller的设置没有问题啊。那么为什么在后来的读取中MAC地址会改变呢,我在反复对比了程序后发现,原来都是cache搞得鬼。

       我们知道44B0内部是有8K的internal memory,这部分memory可以有三种用途。数据手册上的描述如下:The CPU wrapper has an 8-Kbyte internal memory. The internal memory can be used in three ways. First the 8-Kbyte memory can be used as an 8KB unified (instruction/data) cache. Second, the internal memory can be used as a 4-Kbyte unified cache and a 4-Kbyte internal SRAM. Third, the internal memory can be used wholly as an 8-Kbyte internal SRAM.

前两种方式都是作为cache使用的,如果作为cache使用那么是会缓存最近读写的数据的,然而在对外部设备(RTL8019)进行读写时,如果缓存了上次读取的数据,那么下次再次读取时就不会向I/O发送真实的命令,而是会直接取到cache中数据送给CPU。然而,cache中的数据是可能会被改变的,而不从外部设备的寄存器中读取数据也不是程序员设计的本意,因此这是就会出错了。这也就是上面我提到的发现MAC地址寄存器中的数值与设置的数值不一样的原因,其实我的程序后面读到的数据根本就不是真正从RTL8019的registers中读取的,而是从cache中取到的。为了解决这种不一致的问题,在对外部设备操作时通常都是要关闭cache的。

       之前,一直在有MMU的ARM处理器上开发程序,知道对于外设I/O的地址空间在设置其page entry属性时必须将其设置为uncached,这样才能保证cache不会对I/O通信造成影响。而44B0中既没有MMU也没有MPU,因此在对外部设备操作前只能采取先关闭cache,然后操作,操作结束后再开启cache的方法了。

       以上,我个人的一点分析,不对之处还望指正。

      

       PS:各种数据都表明,cache对处理器性能的提升是很重要的,尤其是在那些对于性能要求较高的场合往往必须要合理高效的利用cache才能实现设计目标,因此掌握如何正确的操作cache也是成为高级嵌入式程序员的必备技能之一吧。


抱歉!评论已关闭.