Question

I have implemented a linux kernel driver which uses deferred IO mechanism to track the changes in framebuffer node.

static struct fb_deferred_io fb_defio = {
        .delay          = HZ/2,
        .deferred_io    = fb_dpy_deferred_io,
};

Per say the registered framebuffer node is /dev/graphics/fb1.

The sample application code to access this node is:

fbfd = open("/dev/graphics/fb1", O_RDWR);
if (!fbfd) {
    printf("error\n");
    exit(0);
}
screensize = 540*960*4;
/* Map the device to memory */
fbp = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                   fbfd, 0);
if ((int)fbp == -1) {
    printf("Error: failed to start framebuffer device to memory.");
}

int grey = 0x1;
    for(cnt = 0; cnt < screensize; cnt++)
            *(fbp + cnt) = grey<<4|grey;

This would fill up entire fb1 node with 1's.

The issue now is at the kernel driver when i try to read the entire buffer I find data mismatch at different locations.

The buffer in kernel is mapped as:

par->buffer =  dma_alloc_coherent(dev, roundup((dpyw*dpyh*BPP/8), PAGE_SIZE),(dma_addr_t *) &DmaPhysBuf, GFP_KERNEL);
if (!par->buffer) {
        printk(KERN_WARNING "probe: dma_alloc_coherent failed.\n");
        goto err_vfree;
}

and finally the buffer is registered through register_framebuffer function.

On reading the source buffer I find that at random locations the data is not been written instead the old data is reflected.

For example:

At buffer location 3964 i was expecting 11111111 but i found FF00FF00.

On running the same application program with value of grey changed to 22222222

At buffer location 3964 i was expecting 22222222 but i found 11111111

It looks like there is some delayed write in the buffer. Is there any solution to this effect, because of partially wrong data my image is getting corrupted.

Please let me know if any more information is required.

Note: Looks like an issue of mapped buffer being cacheable or not. Its a lazy write to copy the data from cache to ram. Need to make sure that the data is copied properly but how still no idea.. :-(

Was it helpful?

Solution 3

Well eventually i found a better way to solve the issue. The data written through app at mmaped device node is first written in cache which is later written in RAM through delayed write policy. In order to make sure that the data is flushed properly we need to call the flush function in kernel. I used

dmac_flush_range((void *)pSrc, (void *)pSrc + bufSize);

to flush the data completely so that the kernel receives a clean data.

OTHER TIPS

"Deferred io" means that frame buffer memory is not really mapped to a display device. Rather, it's an ordinary memory area shared between user process and kernel driver. Thus it needs to be "synced" for kernel to actually do anything about it:

msync(fbp, screensize, MS_SYNC);

Calling fsync(fbfd) may also work.

You may also try calling ioctl(fbfd, FBIO_WAITFORVSYNC, 0) if your driver supports it. The call will make your application wait until vsync happens and the frame buffer data was definitely transferred to the device.

I was having a similar issue where I was having random artifacts displaying on the screen. Originally, the framebuffer driver was not using dma at all.

I tried the suggestion of using msync(), which improved the situation (artifacts happened less frequently), but it did not completely solve the issue.

After doing some research I came to the conclusion that I need to use dma memory because it is not cached. There is still the issue with mmap because it is mapping the kernel memory to userspace. However, I found that there is already a function in the kernel to handle this.

So, my solution was in my framebuffer driver, set the mmap function:

static int my_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
        return dma_mmap_coherent(info->dev, vma, info->screen_base,
                                 info->fix.smem_start, info->fix.smem_len);
}

static struct fb_ops my_fb_ops = {
        ...
        .fb_mmap = my_fb_mmap,
};

And then in the probe function:

struct fb_info *info;
struct my_fb_par *par;
dma_addr_t dma_addr;
char *buf

info = framebuffer_alloc(sizeof(struct my_fb_par), &my_parent->dev);
...
buf = dma_alloc_coherent(info->dev, MY_FB_SIZE, dma_addr, GFP_KERNEL);
...
info->screen_base = buf;
info->fbops = &my_fb_ops;
info->fix = my_fb_fix;
info->fix.smem_start = dma_addr;
info->fix.smem_len = MY_FB_SIZE;
...
par = info->par
...
par->buffer = buf;

Obviously, I've left out the error checking and unwinding, but hopefully I have touched on all of the important parts.

Note: Comments in the kernel source say that dmac_flush_range() is for private use only.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top