提交 27a90700 编写于 作者: K Kai Jiang 提交者: Greg Kroah-Hartman

uio: Support physical addresses >32 bits on 32-bit systems

To support >32-bit physical addresses for UIO_MEM_PHYS type we need to
extend the width of 'addr' in struct uio_mem.  Numerous platforms like
embedded PPC, ARM, and X86 have support for systems with larger physical
address than logical.

Since 'addr' may contain a physical, logical, or virtual address the
easiest solution is to just change the type to 'phys_addr_t' which
should always be greater than or equal to the sizeof(void *) such that
it can properly hold any of the address types.

For physical address we can support up to a 44-bit physical address on a
typical 32-bit system as we utilize remap_pfn_range() for the mapping of
the memory region and pfn's are represnted by shifting the address by
the page size (typically 4k).
Signed-off-by: NKai Jiang <Kai.Jiang@freescale.com>
Signed-off-by: NMinghuan Lian <Minghuan.Lian@freescale.com>
Signed-off-by: NKumar Gala <galak@kernel.crashing.org>
Signed-off-by: NHans J. Koch <hjk@hansjkoch.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 c4253cb0
...@@ -529,7 +529,7 @@ memory (e.g. allocated with <function>kmalloc()</function>). There's also ...@@ -529,7 +529,7 @@ memory (e.g. allocated with <function>kmalloc()</function>). There's also
</para></listitem> </para></listitem>
<listitem><para> <listitem><para>
<varname>unsigned long addr</varname>: Required if the mapping is used. <varname>phys_addr_t addr</varname>: Required if the mapping is used.
Fill in the address of your memory block. This address is the one that Fill in the address of your memory block. This address is the one that
appears in sysfs. appears in sysfs.
</para></listitem> </para></listitem>
......
...@@ -69,7 +69,7 @@ static ssize_t map_name_show(struct uio_mem *mem, char *buf) ...@@ -69,7 +69,7 @@ static ssize_t map_name_show(struct uio_mem *mem, char *buf)
static ssize_t map_addr_show(struct uio_mem *mem, char *buf) static ssize_t map_addr_show(struct uio_mem *mem, char *buf)
{ {
return sprintf(buf, "0x%lx\n", mem->addr); return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr);
} }
static ssize_t map_size_show(struct uio_mem *mem, char *buf) static ssize_t map_size_show(struct uio_mem *mem, char *buf)
...@@ -79,7 +79,7 @@ static ssize_t map_size_show(struct uio_mem *mem, char *buf) ...@@ -79,7 +79,7 @@ static ssize_t map_size_show(struct uio_mem *mem, char *buf)
static ssize_t map_offset_show(struct uio_mem *mem, char *buf) static ssize_t map_offset_show(struct uio_mem *mem, char *buf)
{ {
return sprintf(buf, "0x%lx\n", mem->addr & ~PAGE_MASK); return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr & ~PAGE_MASK);
} }
struct map_sysfs_entry { struct map_sysfs_entry {
...@@ -634,8 +634,7 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -634,8 +634,7 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
page = virt_to_page(idev->info->mem[mi].addr + offset); page = virt_to_page(idev->info->mem[mi].addr + offset);
else else
page = vmalloc_to_page((void *)idev->info->mem[mi].addr page = vmalloc_to_page((void *)(unsigned long)idev->info->mem[mi].addr + offset);
+ offset);
get_page(page); get_page(page);
vmf->page = page; vmf->page = page;
return 0; return 0;
......
...@@ -23,7 +23,10 @@ struct uio_map; ...@@ -23,7 +23,10 @@ struct uio_map;
/** /**
* struct uio_mem - description of a UIO memory region * struct uio_mem - description of a UIO memory region
* @name: name of the memory region for identification * @name: name of the memory region for identification
* @addr: address of the device's memory * @addr: address of the device's memory (phys_addr is used since
* addr can be logical, virtual, or physical & phys_addr_t
* should always be large enough to handle any of the
* address types)
* @size: size of IO * @size: size of IO
* @memtype: type of memory addr points to * @memtype: type of memory addr points to
* @internal_addr: ioremap-ped version of addr, for driver internal use * @internal_addr: ioremap-ped version of addr, for driver internal use
...@@ -31,7 +34,7 @@ struct uio_map; ...@@ -31,7 +34,7 @@ struct uio_map;
*/ */
struct uio_mem { struct uio_mem {
const char *name; const char *name;
unsigned long addr; phys_addr_t addr;
unsigned long size; unsigned long size;
int memtype; int memtype;
void __iomem *internal_addr; void __iomem *internal_addr;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册