Re: [PATCH v7] Add udmabuf misc device
> > >> +if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > > >> +return VM_FAULT_SIGBUS; > > > > > > Just curious, when do you expect this to happen ? > > > > It should not. If it actually happens it would be a bug somewhere, > > thats why the WARN_ON. > > But you seem to consider that this condition that should never happen still > has a high enough chance of happening that it's worth a WARN_ON(). I was > wondering why this one in particular, and not other conditions that also > can't > happen and are not checked through the code. Added it while writing the code, to get any coding mistake I make flagged right away instead of things exploding later on. I can drop it. > > >> +ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > > > > > > sizeof(*ubuf) > > > > Why? Should not make a difference ... > > Because the day we replace > > struct udmabuf *ubuf; > > with > > struct udmabuf_ext *ubuf; > > and forget to change the next line, we'll introduce a bug. That's why > sizeof(variable) is preferred over sizeof(type). Another reason is that I can > easily see that > > ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); > > is correct, while using sizeof(type) requires me to go and look up the > declaration of the variable. So it simplifies review, ok, will change it. BTW: Maybe the kernel should pick up a neat trick from glib: g_new0() is a macro which takes the type instead of the size as first argument, and it casts the return value to that type. So the compiler will throw warnings in case of a mismatch. That'll work better than depending purely on the coder being careful and review catching the remaining issues. cheers, Gerd ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v7] Add udmabuf misc device
On Tue, Sep 11, 2018 at 11:50 AM, Laurent Pinchart wrote: > Hi Gerd, > > On Tuesday, 11 September 2018 09:50:14 EEST Gerd Hoffmann wrote: >> Hi, >> >> >> +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) >> > >> > Why do you start at 0x42 if you reserve the 0x40-0x4f range ? >> >> No particular strong reason, just that using 42 was less boring than >> starting with 0x40. >> >> >> +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct >> >> udmabuf_create_list) >> > >> > Where's the documentation ? :-) >> >> Isn't it simple enough? > > No kernel UAPI is simple enough to get away without documenting it. Simplest option would be to throw a bit of kerneldoc into the uapi header, add Documentation/driver-api/dma-buf.rst. -Daniel > >> But, well, yes, I guess I can add some kerneldoc comments. >> >> >> +static int udmabuf_vm_fault(struct vm_fault *vmf) >> >> +{ >> >> + struct vm_area_struct *vma = vmf->vma; >> >> + struct udmabuf *ubuf = vma->vm_private_data; >> >> + >> >> + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) >> >> + return VM_FAULT_SIGBUS; >> > >> > Just curious, when do you expect this to happen ? >> >> It should not. If it actually happens it would be a bug somewhere, >> thats why the WARN_ON. > > But you seem to consider that this condition that should never happen still > has a high enough chance of happening that it's worth a WARN_ON(). I was > wondering why this one in particular, and not other conditions that also can't > happen and are not checked through the code. > >> >> + struct udmabuf *ubuf; >> >> >> >> + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); >> > >> > sizeof(*ubuf) >> >> Why? Should not make a difference ... > > Because the day we replace > > struct udmabuf *ubuf; > > with > > struct udmabuf_ext *ubuf; > > and forget to change the next line, we'll introduce a bug. That's why > sizeof(variable) is preferred over sizeof(type). Another reason is that I can > easily see that > > ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); > > is correct, while using sizeof(type) requires me to go and look up the > declaration of the variable. > >> >> + memfd = fget(list[i].memfd); >> >> + if (!memfd) >> >> + goto err_put_pages; >> >> + if (!shmem_mapping(file_inode(memfd)->i_mapping)) >> >> + goto err_put_pages; >> >> + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); >> >> + if (seals == -EINVAL || >> >> + (seals & SEALS_WANTED) != SEALS_WANTED || >> >> + (seals & SEALS_DENIED) != 0) >> >> + goto err_put_pages; >> > >> > All these conditions will return -EINVAL. I'm not familiar with the memfd >> > API, should some error conditions return a different error code to make >> > them distinguishable by userspace ? >> >> Hmm, I guess EBADFD would be reasonable in case the file handle isn't a >> memfd. Other suggestions? > > I'll let others comment on this as I don't feel qualified to pick proper error > codes, not being familiar with the memfd API. > >> I'll prepare a fixup patch series addressing most of the other >> review comments. > > -- > Regards, > > Laurent Pinchart > > > -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v7] Add udmabuf misc device
Hi Gerd, On Tuesday, 11 September 2018 09:50:14 EEST Gerd Hoffmann wrote: > Hi, > > >> +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > > > > Why do you start at 0x42 if you reserve the 0x40-0x4f range ? > > No particular strong reason, just that using 42 was less boring than > starting with 0x40. > > >> +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct > >> udmabuf_create_list) > > > > Where's the documentation ? :-) > > Isn't it simple enough? No kernel UAPI is simple enough to get away without documenting it. > But, well, yes, I guess I can add some kerneldoc comments. > > >> +static int udmabuf_vm_fault(struct vm_fault *vmf) > >> +{ > >> + struct vm_area_struct *vma = vmf->vma; > >> + struct udmabuf *ubuf = vma->vm_private_data; > >> + > >> + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > >> + return VM_FAULT_SIGBUS; > > > > Just curious, when do you expect this to happen ? > > It should not. If it actually happens it would be a bug somewhere, > thats why the WARN_ON. But you seem to consider that this condition that should never happen still has a high enough chance of happening that it's worth a WARN_ON(). I was wondering why this one in particular, and not other conditions that also can't happen and are not checked through the code. > >> + struct udmabuf *ubuf; > >> > >> + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > > > > sizeof(*ubuf) > > Why? Should not make a difference ... Because the day we replace struct udmabuf *ubuf; with struct udmabuf_ext *ubuf; and forget to change the next line, we'll introduce a bug. That's why sizeof(variable) is preferred over sizeof(type). Another reason is that I can easily see that ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); is correct, while using sizeof(type) requires me to go and look up the declaration of the variable. > >> + memfd = fget(list[i].memfd); > >> + if (!memfd) > >> + goto err_put_pages; > >> + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > >> + goto err_put_pages; > >> + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > >> + if (seals == -EINVAL || > >> + (seals & SEALS_WANTED) != SEALS_WANTED || > >> + (seals & SEALS_DENIED) != 0) > >> + goto err_put_pages; > > > > All these conditions will return -EINVAL. I'm not familiar with the memfd > > API, should some error conditions return a different error code to make > > them distinguishable by userspace ? > > Hmm, I guess EBADFD would be reasonable in case the file handle isn't a > memfd. Other suggestions? I'll let others comment on this as I don't feel qualified to pick proper error codes, not being familiar with the memfd API. > I'll prepare a fixup patch series addressing most of the other > review comments. -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v7] Add udmabuf misc device
Hi, > > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > > Why do you start at 0x42 if you reserve the 0x40-0x4f range ? No particular strong reason, just that using 42 was less boring than starting with 0x40. > > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > > Where's the documentation ? :-) Isn't it simple enough? But, well, yes, I guess I can add some kerneldoc comments. > > +static int udmabuf_vm_fault(struct vm_fault *vmf) > > +{ > > + struct vm_area_struct *vma = vmf->vma; > > + struct udmabuf *ubuf = vma->vm_private_data; > > + > > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > > + return VM_FAULT_SIGBUS; > > Just curious, when do you expect this to happen ? It should not. If it actually happens it would be a bug somewhere, thats why the WARN_ON. > > + struct udmabuf *ubuf; > > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > > sizeof(*ubuf) Why? Should not make a difference ... > > + memfd = fget(list[i].memfd); > > + if (!memfd) > > + goto err_put_pages; > > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > > + goto err_put_pages; > > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > > + if (seals == -EINVAL || > > + (seals & SEALS_WANTED) != SEALS_WANTED || > > + (seals & SEALS_DENIED) != 0) > > + goto err_put_pages; > > All these conditions will return -EINVAL. I'm not familiar with the memfd > API, > should some error conditions return a different error code to make them > distinguishable by userspace ? Hmm, I guess EBADFD would be reasonable in case the file handle isn't a memfd. Other suggestions? I'll prepare a fixup patch series addressing most of the other review comments. cheers, Gerd ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v7] Add udmabuf misc device
Hi Gerd, Thank you for the patch. CC'ing the linux-api mailing list as this creates a new userspace API. On Monday, 27 August 2018 12:34:44 EEST Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 +++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile [snip] > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 00..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) Why do you start at 0x42 if you reserve the 0x40-0x4f range ? > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) Where's the documentation ? :-) > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 00..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Could you please keep the #include alphabetically sorted ? It helps locating duplicates. > +#include I think you can just #include , no need to use the uapi/ prefix. > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; Just curious, when do you expect this to happen ? > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = _vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; You can return ERR_PTR(-ENOMEM) directly. > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) Shouldn't you propagate the return value from sg_alloc_table_from_pages() ? > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); You can merge
Re: [PATCH v7] Add udmabuf misc device
On Mon, Aug 27, 2018 at 11:34:44AM +0200, Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 > ++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile > > diff --git a/Documentation/ioctl/ioctl-number.txt > b/Documentation/ioctl/ioctl-number.txt > index 13a7c999c0..f2ac672eb7 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -272,6 +272,7 @@ Code Seq#(hex) Include FileComments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.hUSB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 00..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 00..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; > + > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = _vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) >
[PATCH v7] Add udmabuf misc device
A driver to let userspace turn memfd regions into dma-bufs. Use case: Allows qemu create dmabufs for the vga framebuffer or virtio-gpu ressources. Then they can be passed around to display those guest things on the host. To spice client for classic full framebuffer display, and hopefully some day to wayland server for seamless guest window display. qemu test branch: https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf Cc: David Airlie Cc: Tomeu Vizoso Cc: Laurent Pinchart Cc: Daniel Vetter Signed-off-by: Gerd Hoffmann --- Documentation/ioctl/ioctl-number.txt | 1 + include/uapi/linux/udmabuf.h | 33 +++ drivers/dma-buf/udmabuf.c | 287 ++ tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 MAINTAINERS | 16 ++ drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + tools/testing/selftests/drivers/dma-buf/Makefile | 5 + 8 files changed, 447 insertions(+) create mode 100644 include/uapi/linux/udmabuf.h create mode 100644 drivers/dma-buf/udmabuf.c create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 13a7c999c0..f2ac672eb7 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -272,6 +272,7 @@ Code Seq#(hex) Include FileComments 't'90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 'u'00-1F linux/smb_fs.h gone 'u'20-3F linux/uvcvideo.hUSB video class host driver +'u'40-4f linux/udmabuf.h userspace dma-buf misc device 'v'00-1F linux/ext2_fs.h conflict! 'v'00-1F linux/fs.h conflict! 'v'00-0F linux/sonypi.h conflict! diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h new file mode 100644 index 00..46b6532ed8 --- /dev/null +++ b/include/uapi/linux/udmabuf.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_UDMABUF_H +#define _UAPI_LINUX_UDMABUF_H + +#include +#include + +#define UDMABUF_FLAGS_CLOEXEC 0x01 + +struct udmabuf_create { + __u32 memfd; + __u32 flags; + __u64 offset; + __u64 size; +}; + +struct udmabuf_create_item { + __u32 memfd; + __u32 __pad; + __u64 offset; + __u64 size; +}; + +struct udmabuf_create_list { + __u32 flags; + __u32 count; + struct udmabuf_create_item list[]; +}; + +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) + +#endif /* _UAPI_LINUX_UDMABUF_H */ diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c new file mode 100644 index 00..8e24204526 --- /dev/null +++ b/drivers/dma-buf/udmabuf.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct udmabuf { + u32 pagecount; + struct page **pages; +}; + +static int udmabuf_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct udmabuf *ubuf = vma->vm_private_data; + + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) + return VM_FAULT_SIGBUS; + + vmf->page = ubuf->pages[vmf->pgoff]; + get_page(vmf->page); + return 0; +} + +static const struct vm_operations_struct udmabuf_vm_ops = { + .fault = udmabuf_vm_fault, +}; + +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) +{ + struct udmabuf *ubuf = buf->priv; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + vma->vm_ops = _vm_ops; + vma->vm_private_data = ubuf; + return 0; +} + +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, + enum dma_data_direction direction) +{ + struct udmabuf *ubuf = at->dmabuf->priv; + struct sg_table *sg; + + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + goto err1; + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, + 0, ubuf->pagecount << PAGE_SHIFT, + GFP_KERNEL) < 0) + goto err2; + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) + goto err3; + + return sg; + +err3: + sg_free_table(sg); +err2: + kfree(sg); +err1: + return ERR_PTR(-ENOMEM); +} + +static void unmap_udmabuf(struct dma_buf_attachment *at, + struct sg_table *sg, +