Re: [patch] zero-bounce highmem I/O

Gerd Knorr
2001-08-17T10:21:07Z

On Thu, Aug 16, 2001 at 03:56:21PM +0100, Alan Cox wrote:
> > It is video layer, and the video layer should be helping along with
> > these sorts of issues.
>
> Linus refused to let make make the vmalloc helpers generic code, thats
> why we have 8 or 9 different copies some containing old bugs

:-(

> > void video_pci_put_user_pages(struct pci_dev *pdev,
> > struct scatterlist *sg,
> > int npages);
>
> Why video_pci. WHy is this even video related. This is a generic issue

I've moved current bttv's mm stuff to another source file and removed
any bttv-related stuff. Compiles, but isn't fully tested yet. The
first three functions are pretty generic. The videomm_buf probably
isn't useful for anything but video4linux. Depends on the highmem-io
patches as it uses the new scatterlist->page.

Comments? Put that into videodev.[ch] ?

Gerd

------------------------ cut here -----------------------
--- /dev/null Thu Jan 1 01:00:00 1970
+++ video-mm.h Fri Aug 17 11:57:02 2001
@@ -0,0 +1,47 @@
+/*
+ * memory management helpers for video4linux drivers (+others?)
+ */
+
+/*
+ * get the page for a kernel virtual address
+ * (i.e. for vmalloc()ed memory)
+ */
+struct page* videomm_vmalloc_to_page(unsigned long virt);
+
+/*
+ * return a scatterlist for vmalloc()'ed memory block.
+ */
+struct scatterlist* videomm_vmalloc_to_sg(unsigned long virt, int nr_pages);
+
+/*
+ * return a scatterlist for a iobuf
+ */
+struct scatterlist* videomm_iobuf_to_sg(struct kiobuf *iobuf);
+
+/* --------------------------------------------------------------------- */
+
+struct videomm_buf {
+ /* for userland buffer */
+ struct kiobuf *iobuf;
+
+ /* for kernel buffers */
+ void* *vmalloc;
+
+ /* common */
+ struct scatterlist *sglist;
+ int sglen;
+ int nr_pages;
+};
+
+int videomm_init_user_buf(struct videomm_buf *vbuf, unsigned long data,
+ unsigned long size);
+int videomm_init_kernel_buf(struct videomm_buf *vbuf, int nr_pages);
+int videomm_pci_map_buf(struct pci_dev *dev, struct videomm_buf *vbuf);
+int videomm_pci_unmap_buf(struct pci_dev *dev, struct videomm_buf *vbuf);
+int videomm_free_buf(struct videomm_buf *vbuf);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
--- /dev/null Thu Jan 1 01:00:00 1970
+++ video-mm.c Fri Aug 17 11:57:14 2001
@@ -0,0 +1,183 @@
+#include <linux/pci.h>
+#include <linux/iobuf.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "video-mm.h"
+
+struct page*
+videomm_vmalloc_to_page(unsigned long virt)
+{
+ struct page *ret = NULL;
+ pmd_t *pmd;
+ pte_t *pte;
+ pgd_t *pgd;
+
+ pgd = pgd_offset_k(virt);
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, virt);
+ if (!pmd_none(*pmd)) {
+ pte = pte_offset(pmd, virt);
+ if (pte_present(*pte)) {
+ ret = pte_page(*pte);
+ }
+ }
+ }
+ return ret;
+}
+
+struct scatterlist*
+videomm_vmalloc_to_sg(unsigned long virt, int nr_pages)
+{
+ struct scatterlist *sglist;
+ struct page *pg;
+ int i;
+
+ sglist = kmalloc(sizeof(struct scatterlist)*nr_pages, GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ memset(sglist,0,sizeof(struct scatterlist)*nr_pages);
+ for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+ pg = videomm_vmalloc_to_page(virt);
+ if (NULL == pg)
+ goto err;
+ sglist[i].page = pg;
+ sglist[i].length = PAGE_SIZE;
+ }
+ return sglist;
+
+ err:
+ kfree(sglist);
+ return NULL;
+}
+
+#if 1
+/*
+ * this is temporary hack only until there is something generic
+ * for that ...
+ */
+# if defined(__i386__)
+# define NO_DMA(page) (((page) - mem_map) > (0xffffffff >> PAGE_SHIFT))
+# else
+# define NO_DMA(page) (0)
+# endif
+#endif
+
+struct scatterlist*
+videomm_iobuf_to_sg(struct kiobuf *iobuf)
+{
+ struct scatterlist *sglist;
+ int i;
+
+ sglist = kmalloc(sizeof(struct scatterlist) * iobuf->nr_pages,
+ GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ memset(sglist,0,sizeof(struct scatterlist) * iobuf->nr_pages);
+
+ if (NO_DMA(iobuf->maplist[0]))
+ goto no_dma;
+ sglist[0].page = iobuf->maplist[0];
+ sglist[0].offset = iobuf->offset;
+ sglist[0].length = PAGE_SIZE - iobuf->offset;
+ for (i = 1; i < iobuf->nr_pages; i++) {
+ if (NO_DMA(iobuf->maplist[i]))
+ goto no_dma;
+ sglist[i].page = iobuf->maplist[i];
+ sglist[i].length = PAGE_SIZE;
+ }
+ return sglist;
+
+ no_dma:
+ /* FIXME: find a more elegant way than simply fail. */
+ kfree(sglist);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+int videomm_init_user_buf(struct videomm_buf *vbuf, unsigned long data,
+ unsigned long size)
+{
+ int err;
+
+ if (0 != (err = alloc_kiovec(1,&vbuf->iobuf)))
+ return err;
+ if (0 != (err = map_user_kiobuf(READ, vbuf->iobuf, data, size)))
+ return err;
+ vbuf->nr_pages = vbuf->iobuf->nr_pages;
+ return 0;
+}
+
+int videomm_init_kernel_buf(struct videomm_buf *vbuf, int nr_pages)
+{
+ vbuf->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == vbuf->vmalloc)
+ return -ENOMEM;
+ vbuf->nr_pages = nr_pages;
+ return 0;
+}
+
+int videomm_pci_map_buf(struct pci_dev *dev, struct videomm_buf *vbuf)
+{
+ int err;
+
+ if (0 == vbuf->nr_pages)
+ BUG();
+
+ if (vbuf->iobuf) {
+ if (0 != (err = lock_kiovec(1,&vbuf->iobuf,1)))
+ return err;
+ vbuf->sglist = videomm_iobuf_to_sg(vbuf->iobuf);
+ }
+ if (vbuf->vmalloc) {
+ vbuf->sglist = videomm_vmalloc_to_sg
+ ((unsigned long)vbuf->vmalloc,vbuf->nr_pages);
+ }
+ if (NULL == vbuf->sglist)
+ return -ENOMEM;
+ vbuf->sglen = pci_map_sg(dev,vbuf->sglist,vbuf->nr_pages,
+ PCI_DMA_FROMDEVICE);
+ return 0;
+}
+
+int videomm_pci_unmap_buf(struct pci_dev *dev, struct videomm_buf *vbuf)
+{
+ if (!vbuf->sglen)
+ BUG();
+
+ pci_unmap_sg(dev,vbuf->sglist,vbuf->iobuf->nr_pages,
+ PCI_DMA_FROMDEVICE);
+ kfree(vbuf->sglist);
+ vbuf->sglist = NULL;
+ vbuf->sglen = 0;
+ if (vbuf->iobuf)
+ unlock_kiovec(1,&vbuf->iobuf);
+ return 0;
+}
+
+int videomm_free_buf(struct videomm_buf *vbuf)
+{
+ if (vbuf->sglen)
+ BUG();
+
+ if (vbuf->iobuf) {
+ unmap_kiobuf(vbuf->iobuf);
+ free_kiovec(1,&vbuf->iobuf);
+ vbuf->iobuf = NULL;
+ }
+ if (vbuf->vmalloc) {
+ vfree(vbuf->vmalloc);
+ vbuf->vmalloc = NULL;
+ }
+ return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */