aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorSonny Rao <sonnyrao@us.ibm.com>2009-06-18 11:13:04 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-26 00:37:26 -0400
commit04a85d1234d7e1682a612565e663e6b760918643 (patch)
tree62acf7f52104c71748e6d2884d0389c146b6e6bf /drivers/char
parente4031d52c57b17c76bbdb15fcf1a32a9f87d9756 (diff)
powerpc/BSR: Fix BSR to allow mmap of small BSR on 64k kernel
On Mon, Nov 17, 2008 at 01:26:13AM -0600, Sonny Rao wrote: > 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, I took a look at changing the driver to reject a request for > mapping more than a single 4k page, however the only indication we get > of the requested size in the mmap function is the vma size, and this > is always one page at minimum. So, it's not possible to determine if > the user wants one 4k page or more. As I noted in my first response, > there is only one case where this is even possible and I don't think > it is a significant concern. > > I did notice that I left out the check to see if the user is trying to > map more than the device length, so I fixed that. Here's the revised > patch. Alright, I've reworked this now so that if we get one of these cases where there's a bsr that's > 4k and < 64k on a 64k kernel we'll only advertise that it is a 4k BSR to userspace. I think this is the best solution since user programs are only supposed to look at sysfs to determine how much can be mapped, and libbsr does this as well. Please consider for 2.6.31 as a fix, thanks. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/bsr.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 7d9fd8a8dfd0..c02db01f736e 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -27,6 +27,7 @@
27#include <linux/cdev.h> 27#include <linux/cdev.h>
28#include <linux/list.h> 28#include <linux/list.h>
29#include <linux/mm.h> 29#include <linux/mm.h>
30#include <asm/pgtable.h>
30#include <asm/io.h> 31#include <asm/io.h>
31 32
32/* 33/*
@@ -118,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
118{ 119{
119 unsigned long size = vma->vm_end - vma->vm_start; 120 unsigned long size = vma->vm_end - vma->vm_start;
120 struct bsr_dev *dev = filp->private_data; 121 struct bsr_dev *dev = filp->private_data;
122 int ret;
121 123
122 if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
123 return -EINVAL;
124
125 vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
126 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 124 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
127 125
128 if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT, 126 /* check for the case of a small BSR device and map one 4k page for it*/
129 size, vma->vm_page_prot)) 127 if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
128 ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
129 vma->vm_page_prot);
130 else if (size <= dev->bsr_len)
131 ret = io_remap_pfn_range(vma, vma->vm_start,
132 dev->bsr_addr >> PAGE_SHIFT,
133 size, vma->vm_page_prot);
134 else
135 return -EINVAL;
136
137 if (ret)
130 return -EAGAIN; 138 return -EAGAIN;
131 139
132 return 0; 140 return 0;
@@ -206,6 +214,11 @@ static int bsr_add_node(struct device_node *bn)
206 cur->bsr_stride = bsr_stride[i]; 214 cur->bsr_stride = bsr_stride[i];
207 cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); 215 cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
208 216
217 /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
218 /* we can only map 4k of it, so only advertise the 4k in sysfs */
219 if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
220 cur->bsr_len = 4096;
221
209 switch(cur->bsr_bytes) { 222 switch(cur->bsr_bytes) {
210 case 8: 223 case 8:
211 cur->bsr_type = BSR_8; 224 cur->bsr_type = BSR_8;