2008-07-18 05:03:58

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 00/06] uio: Various minor changes

Hi everyone,

Here comes a few UIO changes that I've had in my queue for a while.

[PATCH 01/06] uio: Use struct_uio_mem instead of index
[PATCH 02/06] uio: Pass struct uio_mem to mmap functions
[PATCH 03/06] uio: Remove vma->vm_private_data from uio_find_mem()
[PATCH 04/06] uio: Store struct uio_mem ptr in vma->vm_private_data
[PATCH 05/06] uio: Remove redundant vma->vm_flags setup code
[PATCH 06/06] uio: Support multiple UIO_MEM_LOGICAL/VIRTUAL pages

Mostly small cleanups or performance improvements, except the last one
which contains a fix for unsupported multi-page LOGICAL/VIRTUAL maps.

Signed-off-by: Magnus Damm <[email protected]>
---

Documentation/DocBook/uio-howto.tmpl | 2
drivers/uio/uio.c | 91 +++++++++++++++-------------------
include/linux/uio_driver.h | 1
3 files changed, 44 insertions(+), 50 deletions(-)


2008-07-18 05:04:21

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 01/06] uio: Use struct_uio_mem instead of index

From: Magnus Damm <[email protected]>

This patch teaches the UIO code to make use of struct uio_mem pointers.
The code is converted from:
index = uio_find_mem_index()
do_something(idev->info->mem[index].member)
to
mem = uio_find_mem()
do_something(mem->member)

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/uio/uio.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

--- 0001/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:39:49.000000000 +0900
@@ -427,18 +427,18 @@ static ssize_t uio_read(struct file *fil
return retval;
}

-static int uio_find_mem_index(struct vm_area_struct *vma)
+static struct uio_mem *uio_find_mem(struct vm_area_struct *vma)
{
int mi;
struct uio_device *idev = vma->vm_private_data;

for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
if (idev->info->mem[mi].size == 0)
- return -1;
+ break;
if (vma->vm_pgoff == mi)
- return mi;
+ return &idev->info->mem[mi];
}
- return -1;
+ return NULL;
}

static void uio_vma_open(struct vm_area_struct *vma)
@@ -456,16 +456,16 @@ static void uio_vma_close(struct vm_area
static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
+ struct uio_mem *imem = uio_find_mem(vma);
struct page *page;

- int mi = uio_find_mem_index(vma);
- if (mi < 0)
+ if (!imem)
return VM_FAULT_SIGBUS;

- if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
- page = virt_to_page(idev->info->mem[mi].addr);
+ if (imem->memtype == UIO_MEM_LOGICAL)
+ page = virt_to_page(imem->addr);
else
- page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
+ page = vmalloc_to_page((void *)imem->addr);
get_page(page);
vmf->page = page;
return 0;
@@ -479,9 +479,9 @@ static struct vm_operations_struct uio_v

static int uio_mmap_physical(struct vm_area_struct *vma)
{
- struct uio_device *idev = vma->vm_private_data;
- int mi = uio_find_mem_index(vma);
- if (mi < 0)
+ struct uio_mem *imem = uio_find_mem(vma);
+
+ if (!imem)
return -EINVAL;

vma->vm_flags |= VM_IO | VM_RESERVED;
@@ -490,7 +490,7 @@ static int uio_mmap_physical(struct vm_a

return remap_pfn_range(vma,
vma->vm_start,
- idev->info->mem[mi].addr >> PAGE_SHIFT,
+ imem->addr >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
@@ -507,7 +507,7 @@ static int uio_mmap(struct file *filep,
{
struct uio_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev;
- int mi;
+ struct uio_mem *imem;
unsigned long requested_pages, actual_pages;
int ret = 0;

@@ -516,12 +516,12 @@ static int uio_mmap(struct file *filep,

vma->vm_private_data = idev;

- mi = uio_find_mem_index(vma);
- if (mi < 0)
+ imem = uio_find_mem(vma);
+ if (!imem)
return -EINVAL;

requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+ actual_pages = (imem->size + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (requested_pages > actual_pages)
return -EINVAL;

@@ -530,7 +530,7 @@ static int uio_mmap(struct file *filep,
return ret;
}

- switch (idev->info->mem[mi].memtype) {
+ switch (imem->memtype) {
case UIO_MEM_PHYS:
return uio_mmap_physical(vma);
case UIO_MEM_LOGICAL:

2008-07-18 05:04:34

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 02/06] uio: Pass struct uio_mem to mmap functions

From: Magnus Damm <[email protected]>

This patch makes the UIO code pass a struct uio_mem pointer to the
mmap functions. This change allows us to remove one uio_find_mem()
call and an error check.

The error check can be removed since the struct uio_mem pointer has
already been verified in uio_mmap().

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/uio/uio.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)

--- 0002/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:40:42.000000000 +0900
@@ -477,17 +477,10 @@ static struct vm_operations_struct uio_v
.fault = uio_vma_fault,
};

-static int uio_mmap_physical(struct vm_area_struct *vma)
+static int uio_mmap_physical(struct vm_area_struct *vma, struct uio_mem *imem)
{
- struct uio_mem *imem = uio_find_mem(vma);
-
- if (!imem)
- return -EINVAL;
-
vma->vm_flags |= VM_IO | VM_RESERVED;
-
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
return remap_pfn_range(vma,
vma->vm_start,
imem->addr >> PAGE_SHIFT,
@@ -495,7 +488,7 @@ static int uio_mmap_physical(struct vm_a
vma->vm_page_prot);
}

-static int uio_mmap_logical(struct vm_area_struct *vma)
+static int uio_mmap_logical(struct vm_area_struct *vma, struct uio_mem *imem)
{
vma->vm_flags |= VM_RESERVED;
vma->vm_ops = &uio_vm_ops;
@@ -532,10 +525,10 @@ static int uio_mmap(struct file *filep,

switch (imem->memtype) {
case UIO_MEM_PHYS:
- return uio_mmap_physical(vma);
+ return uio_mmap_physical(vma, imem);
case UIO_MEM_LOGICAL:
case UIO_MEM_VIRTUAL:
- return uio_mmap_logical(vma);
+ return uio_mmap_logical(vma, imem);
default:
return -EINVAL;
}

2008-07-18 05:04:50

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 03/06] uio: Remove vma->vm_private_data from uio_find_mem()

From: Magnus Damm <[email protected]>

Pass along a struct uio_device pointer to uio_find_mem() so we can
remove the vma->vm_private_data usage. This allows us to store
different data in vma->vm_private_data in the future.

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/uio/uio.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

--- 0003/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:42:21.000000000 +0900
@@ -427,10 +427,10 @@ static ssize_t uio_read(struct file *fil
return retval;
}

-static struct uio_mem *uio_find_mem(struct vm_area_struct *vma)
+static struct uio_mem *uio_find_mem(struct uio_device *idev,
+ struct vm_area_struct *vma)
{
int mi;
- struct uio_device *idev = vma->vm_private_data;

for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
if (idev->info->mem[mi].size == 0)
@@ -456,7 +456,7 @@ static void uio_vma_close(struct vm_area
static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
- struct uio_mem *imem = uio_find_mem(vma);
+ struct uio_mem *imem = uio_find_mem(idev, vma);
struct page *page;

if (!imem)
@@ -507,9 +507,7 @@ static int uio_mmap(struct file *filep,
if (vma->vm_end < vma->vm_start)
return -EINVAL;

- vma->vm_private_data = idev;
-
- imem = uio_find_mem(vma);
+ imem = uio_find_mem(idev, vma);
if (!imem)
return -EINVAL;

@@ -523,6 +521,8 @@ static int uio_mmap(struct file *filep,
return ret;
}

+ vma->vm_private_data = idev;
+
switch (imem->memtype) {
case UIO_MEM_PHYS:
return uio_mmap_physical(vma, imem);

2008-07-18 05:05:10

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 04/06] uio: Store struct uio_mem ptr in vma->vm_private_data

From: Magnus Damm <[email protected]>

Store a struct uio_mem pointer in vma->vm_private_data. This improves
performance since it allows us to remove a call to uio_find_mem()
from uio_vma_fault(). This change also moves the vma_count member from
struct uio_device to struct uio_mem.

The VM_FAULT_SIGBUS error case in uio_vma_fault() case is simply
removed since we've verified the struct uio_mem pointer earlier when
setting up the vma->vm_private_data.

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/uio/uio.c | 17 ++++++-----------
include/linux/uio_driver.h | 1 +
2 files changed, 7 insertions(+), 11 deletions(-)

--- 0004/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:43:22.000000000 +0900
@@ -32,7 +32,6 @@ struct uio_device {
atomic_t event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
- int vma_count;
struct uio_info *info;
struct kobject *map_dir;
};
@@ -443,25 +442,21 @@ static struct uio_mem *uio_find_mem(stru

static void uio_vma_open(struct vm_area_struct *vma)
{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count++;
+ struct uio_mem *imem = vma->vm_private_data;
+ imem->vma_count++;
}

static void uio_vma_close(struct vm_area_struct *vma)
{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count--;
+ struct uio_mem *imem = vma->vm_private_data;
+ imem->vma_count--;
}

static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- struct uio_device *idev = vma->vm_private_data;
- struct uio_mem *imem = uio_find_mem(idev, vma);
+ struct uio_mem *imem = vma->vm_private_data;
struct page *page;

- if (!imem)
- return VM_FAULT_SIGBUS;
-
if (imem->memtype == UIO_MEM_LOGICAL)
page = virt_to_page(imem->addr);
else
@@ -521,7 +516,7 @@ static int uio_mmap(struct file *filep,
return ret;
}

- vma->vm_private_data = idev;
+ vma->vm_private_data = imem;

switch (imem->memtype) {
case UIO_MEM_PHYS:
--- 0001/include/linux/uio_driver.h
+++ work/include/linux/uio_driver.h 2008-07-18 12:43:22.000000000 +0900
@@ -34,6 +34,7 @@ struct uio_mem {
int memtype;
void __iomem *internal_addr;
struct uio_map *map;
+ int vma_count;
};

#define MAX_UIO_MAPS 5

2008-07-18 05:05:38

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 05/06] uio: Remove redundant vma->vm_flags setup code

From: Magnus Damm <[email protected]>

Remove redundant VM_IO | VM_RESERVED setup code since remap_pfn_range()
already sets them for us.

Signed-off-by: Magnus Damm <[email protected]>
---

drivers/uio/uio.c | 1 -
1 file changed, 1 deletion(-)

--- 0005/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:44:42.000000000 +0900
@@ -474,7 +474,6 @@ static struct vm_operations_struct uio_v

static int uio_mmap_physical(struct vm_area_struct *vma, struct uio_mem *imem)
{
- vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma,
vma->vm_start,

2008-07-18 05:05:51

by Magnus Damm

[permalink] [raw]
Subject: [PATCH 06/06] uio: Support multiple UIO_MEM_LOGICAL/VIRTUAL pages

From: Magnus Damm <[email protected]>

This patch improves the UIO_MEM_LOGICAL and UIO_MEM_VIRTUAL page
fault code to support more than one page of data. Memory allocated
from the slab is however not supported, so a check for that is added
and the documentation gets a little update.

Signed-off-by: Magnus Damm <[email protected]>
---

Documentation/DocBook/uio-howto.tmpl | 2 +-
drivers/uio/uio.c | 10 ++++++++--
2 files changed, 9 insertions(+), 3 deletions(-)

--- 0001/Documentation/DocBook/uio-howto.tmpl
+++ work/Documentation/DocBook/uio-howto.tmpl 2008-07-18 12:45:22.000000000 +0900
@@ -376,7 +376,7 @@ Here's a description of the fields of <v
<varname>int memtype</varname>: Required if the mapping is used. Set this to
<varname>UIO_MEM_PHYS</varname> if you you have physical memory on your
card to be mapped. Use <varname>UIO_MEM_LOGICAL</varname> for logical
-memory (e.g. allocated with <function>kmalloc()</function>). There's also
+memory (e.g. allocated with <function>alloc_pages()</function>). There's also
<varname>UIO_MEM_VIRTUAL</varname> for virtual memory.
</para></listitem>

--- 0006/drivers/uio/uio.c
+++ work/drivers/uio/uio.c 2008-07-18 12:49:38.000000000 +0900
@@ -455,12 +455,15 @@ static void uio_vma_close(struct vm_area
static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_mem *imem = vma->vm_private_data;
+ unsigned long vaddr = imem->addr;
struct page *page;

+ vaddr += (vmf->pgoff - vma->vm_pgoff) << PAGE_SHIFT;
+
if (imem->memtype == UIO_MEM_LOGICAL)
- page = virt_to_page(imem->addr);
+ page = virt_to_page(vaddr);
else
- page = vmalloc_to_page((void *)imem->addr);
+ page = vmalloc_to_page((void *)vaddr);
get_page(page);
vmf->page = page;
return 0;
@@ -521,6 +524,9 @@ static int uio_mmap(struct file *filep,
case UIO_MEM_PHYS:
return uio_mmap_physical(vma, imem);
case UIO_MEM_LOGICAL:
+ if (virt_to_page(imem->addr)->flags & (1 << PG_slab))
+ return -EINVAL; /* kmalloc() not supported */
+ /* fall-through */
case UIO_MEM_VIRTUAL:
return uio_mmap_logical(vma, imem);
default:

2008-07-18 15:46:42

by Hans J. Koch

[permalink] [raw]
Subject: Re: [PATCH 00/06] uio: Various minor changes

On Fri, Jul 18, 2008 at 02:04:02PM +0900, Magnus Damm wrote:
> Hi everyone,
>
> Here comes a few UIO changes that I've had in my queue for a while.

Hi Magnus,
thanks a lot for your patches. I'll have a look at them ASAP, but it'll
take a few days. I'm busy moving to a new house ATM...

Greg, could you help reviewing these ?

Thanks,
Hans

>
> [PATCH 01/06] uio: Use struct_uio_mem instead of index
> [PATCH 02/06] uio: Pass struct uio_mem to mmap functions
> [PATCH 03/06] uio: Remove vma->vm_private_data from uio_find_mem()
> [PATCH 04/06] uio: Store struct uio_mem ptr in vma->vm_private_data
> [PATCH 05/06] uio: Remove redundant vma->vm_flags setup code
> [PATCH 06/06] uio: Support multiple UIO_MEM_LOGICAL/VIRTUAL pages
>
> Mostly small cleanups or performance improvements, except the last one
> which contains a fix for unsupported multi-page LOGICAL/VIRTUAL maps.
>
> Signed-off-by: Magnus Damm <[email protected]>
> ---
>
> Documentation/DocBook/uio-howto.tmpl | 2
> drivers/uio/uio.c | 91 +++++++++++++++-------------------
> include/linux/uio_driver.h | 1
> 3 files changed, 44 insertions(+), 50 deletions(-)

2008-07-25 09:12:39

by Magnus Damm

[permalink] [raw]
Subject: Re: [PATCH 00/06] uio: Various minor changes

Hi Hans,

On Sat, Jul 19, 2008 at 12:46 AM, Hans J. Koch <[email protected]> wrote:
> On Fri, Jul 18, 2008 at 02:04:02PM +0900, Magnus Damm wrote:
>> Hi everyone,
>>
>> Here comes a few UIO changes that I've had in my queue for a while.
>
> Hi Magnus,
> thanks a lot for your patches. I'll have a look at them ASAP, but it'll
> take a few days. I'm busy moving to a new house ATM...

No problem. There is nothing in this series that must be included in
2.6.27 in my opinion, so take your time.

I do however wish to have the uio_pdrv_genirq driver included in
2.6.27. I've seen the uio_pdrv driver and the irqcontrol patches in
linux-2.6.git, but the uio_pdrv_genirq driver is still missing...
Should I repost?

Thanks for your help,

/ magnus