Patchwork Fix BSR to allow mmap of small BSR on 64k kernel

login
register
mail settings
Submitter Sonny Rao
Date Nov. 7, 2008, 12:38 a.m.
Message ID <20081107003841.GE7533@us.ibm.com>
Download mbox | patch
Permalink /patch/7642/
State Superseded, archived
Headers show

Comments

Sonny Rao - Nov. 7, 2008, 12:38 a.m.
Fix the BSR driver to allow small BSR devices, which are limited to a
single 4k space, on a 64k page kernel.  Previously the driver would
reject the mmap since the size was smaller than PAGESIZE (or because
the size was greater than the size of the device).  Now, we check for
this case use remap_4k_pfn(). Also, take out code to set vm_flags,
as the remap_pfn functions will do this for us.


Signed-off-by: Sonny Rao <sonnyrao@us.ibm.com>
Paul Mackerras - Nov. 7, 2008, 5:28 a.m.
Sonny Rao writes:

> Fix the BSR driver to allow small BSR devices, which are limited to a
> single 4k space, on a 64k page kernel.  Previously the driver would
> reject the mmap since the size was smaller than PAGESIZE (or because
> the size was greater than the size of the device).  Now, we check for
> this case use remap_4k_pfn(). Also, take out code to set vm_flags,
> as the remap_pfn functions will do this for us.

Thanks.

Do we know that the BSR size will always be 4k if it's not a multiple
of 64k?  Is it possible that we could get 8k, 16k or 32k or BSRs?
If it is possible, what does the user need to be able to do?  Do they
just want to map 4k, or might then want to map the whole thing?

Paul.
Sonny Rao - Nov. 7, 2008, 11:25 p.m.
On Fri, Nov 07, 2008 at 04:28:29PM +1100, Paul Mackerras wrote:
> Sonny Rao writes:
> 
> > Fix the BSR driver to allow small BSR devices, which are limited to a
> > single 4k space, on a 64k page kernel.  Previously the driver would
> > reject the mmap since the size was smaller than PAGESIZE (or because
> > the size was greater than the size of the device).  Now, we check for
> > this case use remap_4k_pfn(). Also, take out code to set vm_flags,
> > as the remap_pfn functions will do this for us.
> 
> Thanks.
> 
> Do we know that the BSR size will always be 4k if it's not a multiple
> of 64k?  Is it possible that we could get 8k, 16k or 32k or BSRs?
> If it is possible, what does the user need to be able to do?  Do they
> just want to map 4k, or might then want to map the whole thing?

Hi Paul, the BSR comes in 4 different sizes, 8, 16, 64, 128.

The 8 byte BSR registers are always contained to 4k pages and are
always representing a piece of a larger BSR, but can be assigned to
individual LPARs.  

The 16 byte BSR is contained in two 4k pages, and so the code as
patched would not allow both 4k pages to be mapped.  However, I don't
see any reason for the user to need both 4k pages.  

To give some background as to why the BSR exists in multiple pages at
all I'll say that one proposed way to use the BSR is to have each
participating cpu "own" a cache-line sized piece of the BSR mapped
page and write only to that piece.  The reasoning is that using this approach,
software could use either a BSR or regular cachable memory for the
barrier operation, and I would not need to know which it is actually
using.  So in this type of scenario, there should be enough
cache-lines sized pieces mappable. In the case of the 16 byte BSR, one
4k page contains 32 128byte cache-line pieces.  So this is enough to
still use the BSR in this way.

The 64 byte BSR is contained in 16 4k-pages -- so one 64k page works
there, and the 128 byte BSR is contained in 32 4k pages.

The case of the 16 byte BSR is the only one where it matters, I can
change the code to map both 4k pages if the user requests it, but I
don't see any extra utility.  For consistency though, maybe we should
reject a request to map more than 4k but less than 64k on a 64k kernel?

Sonny

Patch

Index: common/drivers/char/bsr.c
===================================================================
--- common.orig/drivers/char/bsr.c	2008-11-06 16:43:58.000000000 -0600
+++ common/drivers/char/bsr.c	2008-11-06 18:30:41.000000000 -0600
@@ -27,6 +27,7 @@ 
 #include <linux/cdev.h>
 #include <linux/list.h>
 #include <linux/mm.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 /*
@@ -115,15 +116,23 @@ 
 {
 	unsigned long size   = vma->vm_end - vma->vm_start;
 	struct bsr_dev *dev = filp->private_data;
+	int ret;
 
-	if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
-		return -EINVAL;
+	/* This is legal where we have a BSR on a 4k page but a 64k kernel */
+	if (size > dev->bsr_len)
+		size = dev->bsr_len;
 
-	vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-	if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
-			       size, vma->vm_page_prot))
+	if (dev->bsr_len < PAGE_SIZE)
+		ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
+				   vma->vm_page_prot);
+	else
+		ret = io_remap_pfn_range(vma, vma->vm_start,
+					 dev->bsr_addr >> PAGE_SHIFT,
+					 size, vma->vm_page_prot);
+
+	if (ret)
 		return -EAGAIN;
 
 	return 0;