--- include/video/impact.h (revision 60) +++ include/video/impact.h (revision 61) @@ -334,4 +334,11 @@ #define impact_cmd_hq_484B(a, p, v) ImpactCFifoPCmd64(a, (0x00484b04 + ((p) << 8)), 0, v) */ +struct impact_cf_args +{ + struct winsize box; /* termios.h */ + unsigned long long base; + unsigned bpitch; +}; + #endif /* _IMPACT_H */ --- drivers/video/fbdev/impact.c (revision 60) +++ drivers/video/fbdev/impact.c (revision 63) @@ -81,6 +81,7 @@ * @pool_txphys: txphys[p] = dma_addr(txtbl[p]). * @kpool_virt: virt[p]: txnum[p] page_addr. * @kpool_phys: phys[p][i] = dma_addr(virt[p][i]). + * @kpool_uaddr: kpool_uaddr[p] = DMA-buffer's userland-address * @kpool_size: TBD. * @num_rss: TBD. * @open_flag: TBD. @@ -102,8 +103,9 @@ /* Kernel DMA pools. */ unsigned long **kpool_virt[MAX_POOLS]; unsigned long *kpool_phys[MAX_POOLS]; + unsigned long kpool_uaddr[MAX_POOLS]; u32 kpool_size[MAX_POOLS]; - + /* Board config. */ u32 num_ge; u32 num_rss; @@ -151,6 +153,7 @@ /* ----------------------------------------------------------------------- */ /* Gory details */ +#define PAR(p) (*((struct impact_par *)(p)->par)) #define MMIO (((struct impact_par *)info->par)->mmio_virt) /** @@ -877,6 +880,30 @@ /* ----------------------------------------------------------------------- */ /* Userland access */ +static int +impact_cacheflush(struct fb_info *info, int pool, const struct impact_cf_args *arg) +{ + struct impact_par *par = info->par; + unsigned short w = arg->box.ws_xpixel << 2; + unsigned short h = arg->box.ws_ypixel; + + if (w && h) + { + unsigned long a = arg->bpitch*arg->box.ws_row + (arg->box.ws_col << 2); + unsigned long b = arg->base + par->kpool_size[pool] - w; + + for (a += arg->base; h; h--, a += arg->bpitch) + { + if (!access_ok(VERIFY_WRITE, (void __user*)a, w)) + return -EFAULT; + if (b <= a) + return -EINVAL; + dma_cache_wback_inv(a, w); + } + } + return 0; +} + /** * impact_fb_ioctl - framebuffer ioctl() access (unimplemented). * @info: struct fb_info pointer to framebuffer data. @@ -886,6 +913,33 @@ static int impact_fb_ioctl(struct fb_info *info, u32 cmd, unsigned long arg) { +#ifdef SGI_INDIGO2 + if (TCFLSH == cmd) { + struct impact_par *par = info->par; + static struct impact_cf_args cfpar; + int i; + + if ( copy_from_user(&cfpar, (void __user*)arg, sizeof(cfpar)) ) + return -EFAULT; + + if (!cfpar.base) + return -EINVAL; + + for (i = 0; i < MAX_POOLS; i++) { + if (cfpar.base == par->kpool_uaddr[i]) { + int r = impact_cacheflush(info, i, &cfpar); + /* Might be munmapped behind our back. */ + if (-EFAULT == r) { + printk(KERN_INFO "impact_ioctl: shut down user" + " cache-flush for DMA-pool %d (%p)\n", + i, (void*)cfpar.base); + par->kpool_uaddr[i] = 0; + } + return r; + } + } + } +#endif return -EINVAL; } /* ----------------------------------------------------------------------- */ @@ -912,8 +966,11 @@ switch (offset) { case 0x0000000: - default: +#ifndef SGI_INDIGO2 if (unlikely((offset + size) > 0x200000)) +#else + if (unlikely((offset + size) > 0x400000)) +#endif return -EINVAL; if (unlikely(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))) @@ -947,10 +1004,16 @@ pfn = (par->kpool_phys[pool][i] >> PAGE_SHIFT); ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, vma->vm_page_prot); - if (unlikely(ret)) + if (unlikely(ret)) { + par->kpool_uaddr[pool] = 0; return -EAGAIN; + } start += PAGE_SIZE; } + par->kpool_uaddr[pool] = vma->vm_start; + break; + default: + return -EINVAL; } return 0;