lkml.org 
[lkml]   [2001]   [Aug]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [patch] zero-bounce highmem I/O
    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:
    + */
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 12:57    [W:3.090 / U:1.628 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site