Clear CPU caches for reading system timer on beaglebone

Hi,

I am using TI AM335x BeagleBone. My aim is to get fast and reliable time values from user-space using dmtimer.

When I I read (and print) tick values of DMTimer2 though /dev/mem, I have the following:

2703519715
2703525474
2703527633
2703529333
2703530952
2703532576
2703538448
2703541914
2703543656
2703545281
2703546900

However, when I invoke device driver with mmap operation and then in user space interact with this device, I have a strange behaviour. 
Ticks are repeated periodically: 

1287902680
1287911282
1287911282
1287911282
1287911282
1287911282
1287925948
1287925948
1287925948
1287935869
1287935869
1287935869
1287944825
1287944825
1287950109
1287950109
1287959332

I am not sure, but it looks like L1/L2 caches are overflowed. My question is what can cause this behaviour. And if it is CPU caches, how they can be cleared. 
I found this answer http://stackoverflow.com/questions/3446138/how-to-clear-cpu-l1-and-l2-cache, but I doubt how I can apply this method.
Do you have any suggestions? I will appreciate any help.

If it is necessary, I post here briefly the way how I obtaine these ticks vs driver.
1. remapping of a specific region in kernel space (0x48040000 - DMTIMER2 register start address):


static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
{
  unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
  // generate the correct page frame number
  unsigned long pfn = (0x48040000 + off) >> PAGE_SHIFT;
  // vsize is the requested size of virtual memory  
  unsigned long vsize = vma->vm_end - vma->vm_start;
  // psize is the physical I/O size that is left after the offset has been specified 
  unsigned long psize = 0x48040000 + 32 - off;
  // refuses to map addresses that extend beyond the allowed memory range
  if (vsize > psize)
  {
    return -EINVAL;
  }
  if (remap_pfn_range(vma, vma->vm_start, pfn, vsize, vma->vm_page_prot))
  {
    return
  -EAGAIN;
  }
  vma->vm_ops = &simple_remap_vm_ops;
  simple_vma_open(vma);
  return 0;
}

2. in user space I do it approximately in the following way:


volatile unsigned char* dmt2_regs;
dmt2_regs = (unsigned char*) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
while (true)
{
  uint32_t t0 = * (uint32_t*) ( dmt2_regs + 0x3c );
  std::cout << t0 << std::endl;
} 

dmt2_regs = (unsigned char*) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_NOCACHE, MAP_SHARED, fd, 0);

Hi

I too am working on the timer4 and trying to access the registers using dev/mem. However I get bus error when trying to read the address. Can you let me know how you did this using dev/mem.

My code is posted below:

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include <signal.h>

#define TIMER4_START_addr 0x48044000
#define TIDR 0x00
#define TIOCP_CFG 0x10

int main()
{
   unsigned int reg;

   char *timer_addr = NULL;

   printf("\n Start Pgm");

    int mem, integer;

    if ((mem = open ("/dev/mem", O_RDWR | O_SYNC)) < 0)
    {
        printf("Cannot open /dev/mem\n");

        return 1;
    }

    printf("Opened /dev/mem\n");

    timer_addr = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem, TIMER4_START_addr);

    printf("GPIO mapped to %p\n", timer_addr);

    reg =  *((int*) timer_addr);

    printf("GPIO1 configuration: %x\n", reg);

    return 0;
}

Regards
Anand