Commit 6ee22f53 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-dma

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 04c73690 b0c8809e
......@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/hardware/icst525.h>
......@@ -259,6 +260,17 @@ static int impd1fb_clcd_setup(struct clcd_fb *fb)
return ret;
}
static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
unsigned long start, size;
start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
size = vma->vm_end - vma->vm_start;
return remap_pfn_range(vma, vma->vm_start, start, size,
vma->vm_page_prot);
}
static void impd1fb_clcd_remove(struct clcd_fb *fb)
{
iounmap(fb->fb.screen_base);
......@@ -272,6 +284,7 @@ static struct clcd_board impd1_clcd_data = {
.disable = impd1fb_clcd_disable,
.enable = impd1fb_clcd_enable,
.setup = impd1fb_clcd_setup,
.mmap = impd1fb_clcd_mmap,
.remove = impd1fb_clcd_remove,
};
......
......@@ -444,6 +444,14 @@ static int cp_clcd_setup(struct clcd_fb *fb)
return 0;
}
static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
return dma_mmap_writecombine(&fb->dev->dev, vma,
fb->fb.screen_base,
fb->fb.fix.smem_start,
fb->fb.fix.smem_len);
}
static void cp_clcd_remove(struct clcd_fb *fb)
{
dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
......@@ -456,6 +464,7 @@ static struct clcd_board clcd_data = {
.decode = clcdfb_decode,
.enable = cp_clcd_enable,
.setup = cp_clcd_setup,
.mmap = cp_clcd_mmap,
.remove = cp_clcd_remove,
};
......
......@@ -597,6 +597,14 @@ static int versatile_clcd_setup(struct clcd_fb *fb)
return 0;
}
static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
return dma_mmap_writecombine(&fb->dev->dev, vma,
fb->fb.screen_base,
fb->fb.fix.smem_start,
fb->fb.fix.smem_len);
}
static void versatile_clcd_remove(struct clcd_fb *fb)
{
dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
......@@ -610,6 +618,7 @@ static struct clcd_board clcd_plat_data = {
.disable = versatile_clcd_disable,
.enable = versatile_clcd_enable,
.setup = versatile_clcd_setup,
.mmap = versatile_clcd_mmap,
.remove = versatile_clcd_remove,
};
......
/*
* linux/arch/arm/mm/consistent.c
*
* Copyright (C) 2000-2002 Russell King
* Copyright (C) 2000-2004 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
......@@ -65,6 +65,7 @@ struct vm_region {
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
struct page *vm_pages;
};
static struct vm_region consistent_head = {
......@@ -206,6 +207,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order);
c->vm_pages = page;
/*
* Set the "dma handle"
*/
......@@ -215,6 +218,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
BUG_ON(!pte_none(*pte));
set_page_count(page, 1);
/*
* x86 does not mark the pages reserved...
*/
SetPageReserved(page);
set_pte(pte, mk_pte(page, prot));
page++;
......@@ -264,6 +270,50 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
}
EXPORT_SYMBOL(dma_alloc_writecombine);
static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
unsigned long flags, user_size, kern_size;
struct vm_region *c;
int ret = -ENXIO;
user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
spin_lock_irqsave(&consistent_lock, flags);
c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
spin_unlock_irqrestore(&consistent_lock, flags);
if (c) {
kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
if (vma->vm_pgoff < kern_size ||
user_size <= (kern_size - vma->vm_pgoff)) {
vma->vm_flags |= VM_RESERVED;
ret = remap_pfn_range(vma, vma->vm_start,
page_to_pfn(c->vm_pages),
user_size, vma->vm_page_prot);
}
}
return ret;
}
int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
}
EXPORT_SYMBOL(dma_mmap_coherent);
int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
}
EXPORT_SYMBOL(dma_mmap_writecombine);
/*
* free a page as defined by the above mapping.
*/
......@@ -300,6 +350,10 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
/*
* x86 does not mark the pages reserved...
*/
ClearPageReserved(page);
__free_page(page);
......
......@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
......@@ -300,6 +301,22 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
return 0;
}
static int clcdfb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct clcd_fb *fb = to_clcd(info);
unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
int ret = -EINVAL;
len = info->fix.smem_len;
if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
fb->board->mmap)
ret = fb->board->mmap(fb, vma);
return ret;
}
static struct fb_ops clcdfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = clcdfb_check_var,
......@@ -310,6 +327,7 @@ static struct fb_ops clcdfb_ops = {
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
.fb_mmap = clcdfb_mmap,
};
static int clcdfb_register(struct clcd_fb *fb)
......
......@@ -394,6 +394,20 @@ static int pxafb_blank(int blank, struct fb_info *info)
return 0;
}
static int pxafb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
return -EINVAL;
}
static struct fb_ops pxafb_ops = {
.owner = THIS_MODULE,
.fb_check_var = pxafb_check_var,
......@@ -404,6 +418,7 @@ static struct fb_ops pxafb_ops = {
.fb_imageblit = cfb_imageblit,
.fb_blank = pxafb_blank,
.fb_cursor = soft_cursor,
.fb_mmap = pxafb_mmap,
};
/*
......
......@@ -814,6 +814,33 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
return 0;
}
static int sa1100fb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1; /* skip over the palette */
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
off += start & PAGE_MASK;
vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return io_remap_page_range(vma, vma->vm_start, off,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
static struct fb_ops sa1100fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = sa1100fb_check_var,
......@@ -825,6 +852,7 @@ static struct fb_ops sa1100fb_ops = {
.fb_imageblit = cfb_imageblit,
.fb_blank = sa1100fb_blank,
.fb_cursor = soft_cursor,
.fb_mmap = sa1100fb_mmap,
};
/*
......
......@@ -86,6 +86,22 @@ extern void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle);
/**
* dma_mmap_coherent - map a coherent DMA allocation into user space
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @vma: vm_area_struct describing requested user mapping
* @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
* @size: size of memory originally requested in dma_alloc_coherent
*
* Map a coherent DMA buffer previously allocated by dma_alloc_coherent
* into user space. The coherent DMA buffer must not be freed by the
* driver until the user space mapping has been released.
*/
int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t handle, size_t size);
/**
* dma_alloc_writecombine - allocate writecombining memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
......@@ -103,6 +119,9 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
#define dma_free_writecombine(dev,size,cpu_addr,handle) \
dma_free_coherent(dev,size,cpu_addr,handle)
int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t handle, size_t size);
/**
* dma_map_single - map a single buffer for streaming DMA
......
......@@ -124,6 +124,11 @@ struct clcd_board {
*/
int (*setup)(struct clcd_fb *);
/*
* mmap the framebuffer memory
*/
int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
/*
* Remove platform specific parts of CLCD driver
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment