From: Jeff Garzik <jgarzik@mandrakesoft.com>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: PATCH 2.4.0.10.6: video4linux API update, bttv mmap rewrite
Date: Sat, 28 Oct 2000 13:02:45 -0400 [thread overview]
Message-ID: <39FB06B5.E52682B9@mandrakesoft.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 924 bytes --]
Thought some people here might be interested in this too... Description
quoted below.
--
Jeff Garzik | "Mind if I drive?" -Sam
Building 1024 | "Not if you don't mind me clawing at the
MandrakeSoft | dash and screaming like a cheerleader."
| -Max
> This patch, against 2.4.0-test10-pre6, updates bttv to use the new and
> groovy method of supporting mmap.
>
> Advantages:
> * Code more simple.
> * mmap now only limited to number of free pages in the system (busts vmalloc limits)
> * mmap no longer requires vmalloc, or remap_page_range.
>
> Disadvantages:
> * Requires videodev API update (new member: mmap_vma).
> * KNOWN BUG: If your gbufsize causes a frame to cross a page boundary,
> you lose. The code doesn't support this, and doesn't check for it
> either. Boom. (this is fixable though)
> * Totally untested. I don't own any bttv hardware.
>
[-- Attachment #2: bttv-mmap.patch --]
[-- Type: text/plain, Size: 10777 bytes --]
Index: include/linux/videodev.h
===================================================================
RCS file: /cvsroot/gkernel/linux_2_4/include/linux/videodev.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 videodev.h
--- include/linux/videodev.h 2000/10/22 19:36:11 1.1.1.1
+++ include/linux/videodev.h 2000/10/28 07:31:20
@@ -32,6 +32,7 @@
int busy;
int minor;
devfs_handle_t devfs_handle;
+ int (*mmap_vma)(struct file *, struct vm_area_struct *, struct video_device *);
};
extern int videodev_init(void);
Index: drivers/media/video/bttv-driver.c
===================================================================
RCS file: /cvsroot/gkernel/linux_2_4/drivers/media/video/bttv-driver.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 bttv-driver.c
--- drivers/media/video/bttv-driver.c 2000/10/22 22:02:34 1.1.1.2
+++ drivers/media/video/bttv-driver.c 2000/10/28 07:31:24
@@ -142,16 +142,6 @@
return ret;
}
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
static inline unsigned long kvirt_to_bus(unsigned long adr)
{
unsigned long va, kva, ret;
@@ -163,79 +153,60 @@
return ret;
}
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
+/*
+ * Alloc and free DMA pages for mmap(2)
*/
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = __pa(kva);
- MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static void * rvmalloc(signed long size)
+
+static void free_dmabuffers(struct bttv *btv)
{
- void * mem;
- unsigned long adr, page;
+ unsigned int i;
- mem=vmalloc_32(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_pa(adr);
- mem_map_reserve(virt_to_page(__va(page)));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
+ if (btv->page) {
+ for (i = 0; i < btv->n_pages; i++)
+ if (btv->page[i].cpuaddr)
+ pci_free_consistent (btv->dev, PAGE_SIZE,
+ btv->page[i].cpuaddr,
+ btv->page[i].handle);
+ memset(btv->page, 0, sizeof(btv->page) * btv->n_pages);
+ btv->n_pages = 0;
+ kfree(btv->page);
+ btv->page = NULL;
}
- return mem;
}
-static void rvfree(void * mem, signed long size)
+static int alloc_dmabuffers(struct bttv *btv)
{
- unsigned long adr, page;
-
- if (mem)
- {
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_pa(adr);
- mem_map_unreserve(virt_to_page(__va(page)));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- vfree(mem);
- }
-}
+ unsigned int i;
+ if (btv->page) {
+ printk(KERN_ERR "bttv%d: Double alloc of DMA pages!\n", btv->nr);
+ return 0;
+ }
+ btv->n_pages = (gbuffers * gbufsize) >> PAGE_SHIFT;
+ if ((gbuffers * gbufsize) % PAGE_SIZE)
+ btv->n_pages++;
-/*
- * Create the giant waste of buffer space we need for now
- * until we get DMA to user space sorted out (probably 2.3.x)
- *
- * We only create this as and when someone uses mmap
- */
-
-static int fbuffer_alloc(struct bttv *btv)
-{
- if(!btv->fbuffer)
- btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
- else
- printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
- btv->nr);
- if(!btv->fbuffer)
- return -ENOBUFS;
+ btv->page = kmalloc (sizeof(btv->page) * btv->n_pages, GFP_KERNEL);
+ if (!btv->page) {
+ btv->n_pages = 0;
+ return -ENOMEM;
+ }
+ memset (btv->page, 0, sizeof(btv->page) * btv->n_pages);
+
+ for (i = 0; i < btv->n_pages; i++) {
+ btv->page[i].cpuaddr = pci_alloc_consistent (
+ btv->dev, PAGE_SIZE, &btv->page[i].handle);
+ if (!btv->page[i].cpuaddr)
+ goto err_out;
+ memset(btv->page[i].cpuaddr, 0, PAGE_SIZE);
+ }
+
return 0;
+
+err_out:
+ free_dmabuffers(btv);
+ return -ENOMEM;
}
@@ -1265,13 +1236,13 @@
static int vgrab(struct bttv *btv, struct video_mmap *mp)
{
unsigned int *ro, *re;
- unsigned int *vbuf;
+ unsigned int *vbuf, page, page_ofs;
unsigned long flags;
- if(btv->fbuffer==NULL)
+ if (btv->page == NULL)
{
- if(fbuffer_alloc(btv))
- return -ENOBUFS;
+ int rc = alloc_dmabuffers(btv);
+ if (rc) return rc;
}
if(mp->frame >= gbuffers || mp->frame < 0)
@@ -1294,7 +1265,9 @@
* Ok load up the BT848
*/
- vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame);
+ page = (gbufsize * mp->frame) >> PAGE_SHIFT;
+ page_ofs = (gbufsize * mp->frame) % PAGE_SIZE;
+ vbuf = (unsigned int *) (btv->page[page].cpuaddr + page_ofs);
ro=btv->gbuf[mp->frame].risc;
re=ro+2048;
make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
@@ -1433,9 +1406,8 @@
if (btv->user)
goto out_unlock;
- btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
- ret = -ENOMEM;
- if (!btv->fbuffer)
+ ret = alloc_dmabuffers(btv);
+ if (ret)
goto out_unlock;
btv->gq_in = 0;
@@ -1495,9 +1467,8 @@
* We have allowed it to drain.
*/
- if(btv->fbuffer)
- rvfree((void *) btv->fbuffer, gbuffers*gbufsize);
- btv->fbuffer=0;
+ if (btv->page)
+ free_dmabuffers(btv);
up(&btv->lock);
MOD_DEC_USE_COUNT;
}
@@ -2166,45 +2137,81 @@
return 0;
}
+static struct page * bttv_mm_nopage (struct vm_area_struct * vma,
+ unsigned long address, int write_access)
+{
+ struct bttv *btv = vma->vm_private_data;
+ struct page *dmapage;
+ unsigned long pgoff;
+
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!btv) return NOPAGE_OOM; /* Nothing allocated */
+
+ pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
+ if (pgoff > btv->n_pages) return NOPAGE_SIGBUS;
+
+ dmapage = virt_to_page (btv->page[pgoff].cpuaddr);
+ get_page (dmapage);
+ return dmapage;
+}
+
+#ifndef VM_RESERVE
+static int bttv_mm_swapout (struct page *page, struct file *filp)
+{
+ return 0;
+}
+#endif /* VM_RESERVE */
+
+struct vm_operations_struct bttv_mm_ops = {
+ nopage: bttv_mm_nopage,
+#ifndef VM_RESERVE
+ swapout: bttv_mm_swapout,
+#endif
+};
+
/*
* This maps the vmalloced and reserved fbuffer to user space.
- *
- * FIXME:
- * - PAGE_READONLY should suffice!?
- * - remap_page_range is kind of inefficient for page by page remapping.
- * But e.g. pte_alloc() does not work in modules ... :-(
*/
-static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size)
+static int do_bttv_mmap (struct file *file, struct vm_area_struct *vma,
+ struct bttv *btv)
{
- unsigned long start=(unsigned long) adr;
- unsigned long page,pos;
+ int rc = -EINVAL;
+ unsigned long max_size, size, start, offset;
- if (size>gbuffers*gbufsize)
- return -EINVAL;
- if (!btv->fbuffer) {
- if(fbuffer_alloc(btv))
- return -EINVAL;
- }
- pos=(unsigned long) btv->fbuffer;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start+=PAGE_SIZE;
- pos+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- return 0;
+ max_size = (gbuffers * gbufsize);
+
+ start = vma->vm_start;
+ offset = (vma->vm_pgoff << PAGE_SHIFT);
+ size = vma->vm_end - vma->vm_start;
+
+ /* some basic size/offset sanity checks */
+ if (size > max_size)
+ goto out;
+ if (offset > max_size - size)
+ goto out;
+
+ vma->vm_ops = &bttv_mm_ops;
+ vma->vm_private_data = btv;
+
+#ifdef VM_RESERVE
+ vma->vm_flags |= VM_RESERVE;
+#endif
+
+ rc = 0;
+
+out:
+ return rc;
}
-static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int bttv_mmap_vma(struct file *file, struct vm_area_struct *vma,
+ struct video_device *dev)
{
struct bttv *btv=(struct bttv *)dev;
int r;
down(&btv->lock);
- r=do_bttv_mmap(btv, adr, size);
+ r=do_bttv_mmap(file, vma, btv);
up(&btv->lock);
return r;
}
@@ -2212,20 +2219,18 @@
static struct video_device bttv_template=
{
- "UNSET",
- VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
- VID_HARDWARE_BT848,
- bttv_open,
- bttv_close,
- bttv_read,
- bttv_write,
- NULL,
- bttv_ioctl,
- bttv_mmap,
- bttv_init_done,
- NULL,
- 0,
- -1
+ name: "UNSET",
+ type: VID_TYPE_TUNER|VID_TYPE_CAPTURE|
+ VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
+ hardware: VID_HARDWARE_BT848,
+ open: bttv_open,
+ close: bttv_close,
+ read: bttv_read,
+ write: bttv_write,
+ ioctl: bttv_ioctl,
+ mmap_vma: bttv_mmap_vma,
+ initialize: bttv_init_done,
+ minor: -1,
};
@@ -2753,7 +2758,8 @@
memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
memory to the user */
- btv->fbuffer=NULL;
+ btv->page = NULL;
+ btv->n_pages = 0;
bt848_muxsel(btv, 1);
bt848_set_winsize(btv);
Index: drivers/media/video/bttv.h
===================================================================
RCS file: /cvsroot/gkernel/linux_2_4/drivers/media/video/bttv.h,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 bttv.h
--- drivers/media/video/bttv.h 2000/10/22 22:02:34 1.1.1.2
+++ drivers/media/video/bttv.h 2000/10/28 07:31:24
@@ -251,6 +251,13 @@
unsigned long re;
};
+
+struct bttv_dma {
+ void *cpuaddr;
+ dma_addr_t handle;
+};
+
+
struct bttv {
struct video_device video_dev;
struct video_device radio_dev;
@@ -312,7 +319,9 @@
struct bttv_gbuf *gbuf;
int gqueue[MAX_GBUFFERS];
int gq_in,gq_out,gq_grab,gq_start;
- char *fbuffer;
+
+ struct bttv_dma *page;
+ unsigned int n_pages;
struct bttv_pll_info pll;
unsigned int Fsc;
Index: drivers/media/video/videodev.c
===================================================================
RCS file: /cvsroot/gkernel/linux_2_4/drivers/media/video/videodev.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 videodev.c
--- drivers/media/video/videodev.c 2000/10/22 21:28:40 1.1.1.1
+++ drivers/media/video/videodev.c 2000/10/28 07:31:24
@@ -227,7 +227,9 @@
{
int ret = -EINVAL;
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- if(vfl->mmap) {
+ if (vfl->mmap_vma)
+ return vfl->mmap_vma (file, vma, vfl);
+ if (vfl->mmap) {
lock_kernel();
ret = vfl->mmap(vfl, (char *)vma->vm_start,
(unsigned long)(vma->vm_end-vma->vm_start));
reply other threads:[~2000-10-28 17:03 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=39FB06B5.E52682B9@mandrakesoft.com \
--to=jgarzik@mandrakesoft.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.