xref: /openbsd/sys/dev/pci/drm/drm_gem_dma_helper.c (revision f005ef32)
1*f005ef32Sjsg /* $OpenBSD: drm_gem_dma_helper.c,v 1.3 2024/01/16 23:37:51 jsg Exp $ */
21bb76ff1Sjsg /* $NetBSD: drm_gem_dma_helper.c,v 1.9 2019/11/05 23:29:28 jmcneill Exp $ */
31bb76ff1Sjsg /*-
41bb76ff1Sjsg  * Copyright (c) 2015-2017 Jared McNeill <jmcneill@invisible.ca>
51bb76ff1Sjsg  * All rights reserved.
61bb76ff1Sjsg  *
71bb76ff1Sjsg  * Redistribution and use in source and binary forms, with or without
81bb76ff1Sjsg  * modification, are permitted provided that the following conditions
91bb76ff1Sjsg  * are met:
101bb76ff1Sjsg  * 1. Redistributions of source code must retain the above copyright
111bb76ff1Sjsg  *    notice, this list of conditions and the following disclaimer.
121bb76ff1Sjsg  * 2. Redistributions in binary form must reproduce the above copyright
131bb76ff1Sjsg  *    notice, this list of conditions and the following disclaimer in the
141bb76ff1Sjsg  *    documentation and/or other materials provided with the distribution.
151bb76ff1Sjsg  *
161bb76ff1Sjsg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171bb76ff1Sjsg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181bb76ff1Sjsg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191bb76ff1Sjsg  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201bb76ff1Sjsg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211bb76ff1Sjsg  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221bb76ff1Sjsg  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231bb76ff1Sjsg  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241bb76ff1Sjsg  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251bb76ff1Sjsg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261bb76ff1Sjsg  * SUCH DAMAGE.
271bb76ff1Sjsg  */
281bb76ff1Sjsg 
291bb76ff1Sjsg #include <sys/param.h>
301bb76ff1Sjsg #include <linux/iosys-map.h>
311bb76ff1Sjsg 
321bb76ff1Sjsg #include <drm/drm_device.h>
331bb76ff1Sjsg #include <drm/drm_gem_dma_helper.h>
341bb76ff1Sjsg 
351bb76ff1Sjsg #include <uvm/uvm.h>
361bb76ff1Sjsg 
371bb76ff1Sjsg static const struct drm_gem_object_funcs drm_gem_dma_default_funcs = {
381bb76ff1Sjsg 	.free = drm_gem_dma_free_object,
391bb76ff1Sjsg 	.get_sg_table = drm_gem_dma_get_sg_table,
401bb76ff1Sjsg 	.vmap = drm_gem_dma_vmap,
411bb76ff1Sjsg //	.mmap = drm_gem_dma_mmap,
421bb76ff1Sjsg };
431bb76ff1Sjsg 
441bb76ff1Sjsg static struct drm_gem_dma_object *
drm_gem_dma_create_internal(struct drm_device * ddev,size_t size,struct sg_table * sgt)451bb76ff1Sjsg drm_gem_dma_create_internal(struct drm_device *ddev, size_t size,
461bb76ff1Sjsg     struct sg_table *sgt)
471bb76ff1Sjsg {
481bb76ff1Sjsg 	struct drm_gem_dma_object *obj;
491bb76ff1Sjsg 	int error, nsegs;
501bb76ff1Sjsg 
511bb76ff1Sjsg 	obj = malloc(sizeof(*obj), M_DRM, M_WAITOK | M_ZERO);
521bb76ff1Sjsg 	obj->dmat = ddev->dmat;
531bb76ff1Sjsg 	obj->dmasize = size;
541bb76ff1Sjsg 	obj->base.funcs = &drm_gem_dma_default_funcs;
551bb76ff1Sjsg 
561bb76ff1Sjsg 	if (sgt) {
57667382c7Skettenis 		STUB();
581bb76ff1Sjsg #ifdef notyet
591bb76ff1Sjsg 		error = -drm_prime_sg_to_bus_dmamem(obj->dmat, obj->dmasegs, 1,
601bb76ff1Sjsg 		    &nsegs, sgt);
611bb76ff1Sjsg #endif
621bb76ff1Sjsg 		error = -ENOMEM;
631bb76ff1Sjsg 	} else {
641bb76ff1Sjsg 		error = bus_dmamem_alloc(obj->dmat, obj->dmasize,
651bb76ff1Sjsg 		    PAGE_SIZE, 0, obj->dmasegs, 1, &nsegs,
661bb76ff1Sjsg 		    BUS_DMA_WAITOK);
671bb76ff1Sjsg 	}
681bb76ff1Sjsg 	if (error)
691bb76ff1Sjsg 		goto failed;
701bb76ff1Sjsg 	error = bus_dmamem_map(obj->dmat, obj->dmasegs, nsegs,
711bb76ff1Sjsg 	    obj->dmasize, &obj->vaddr,
721bb76ff1Sjsg 	    BUS_DMA_WAITOK | BUS_DMA_NOCACHE);
731bb76ff1Sjsg 	if (error)
741bb76ff1Sjsg 		goto free;
751bb76ff1Sjsg 	error = bus_dmamap_create(obj->dmat, obj->dmasize, 1,
761bb76ff1Sjsg 	    obj->dmasize, 0, BUS_DMA_WAITOK, &obj->dmamap);
771bb76ff1Sjsg 	if (error)
781bb76ff1Sjsg 		goto unmap;
791bb76ff1Sjsg 	error = bus_dmamap_load(obj->dmat, obj->dmamap, obj->vaddr,
801bb76ff1Sjsg 	    obj->dmasize, NULL, BUS_DMA_WAITOK);
811bb76ff1Sjsg 	if (error)
821bb76ff1Sjsg 		goto destroy;
831bb76ff1Sjsg 
841bb76ff1Sjsg #ifdef notyet
851bb76ff1Sjsg 	if (!sgt)
861bb76ff1Sjsg #endif
871bb76ff1Sjsg 		memset(obj->vaddr, 0, obj->dmasize);
881bb76ff1Sjsg 
891bb76ff1Sjsg 	error = drm_gem_object_init(ddev, &obj->base, size);
901bb76ff1Sjsg 	if (error)
911bb76ff1Sjsg 		goto unload;
921bb76ff1Sjsg 
93667382c7Skettenis 	obj->dma_addr = obj->dmamap->dm_segs[0].ds_addr;
941bb76ff1Sjsg 	return obj;
951bb76ff1Sjsg 
961bb76ff1Sjsg unload:
971bb76ff1Sjsg 	bus_dmamap_unload(obj->dmat, obj->dmamap);
981bb76ff1Sjsg destroy:
991bb76ff1Sjsg 	bus_dmamap_destroy(obj->dmat, obj->dmamap);
1001bb76ff1Sjsg unmap:
1011bb76ff1Sjsg 	bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize);
1021bb76ff1Sjsg free:
1031bb76ff1Sjsg #ifdef notyet
1041bb76ff1Sjsg 	if (obj->sgt)
1051bb76ff1Sjsg 		drm_prime_sg_free(obj->sgt);
1061bb76ff1Sjsg 	else
1071bb76ff1Sjsg #endif
1081bb76ff1Sjsg 		bus_dmamem_free(obj->dmat, obj->dmasegs, nsegs);
1091bb76ff1Sjsg failed:
1101bb76ff1Sjsg 	free(obj, M_DRM, sizeof(*obj));
1111bb76ff1Sjsg 
1121bb76ff1Sjsg 	return NULL;
1131bb76ff1Sjsg }
1141bb76ff1Sjsg 
1151bb76ff1Sjsg struct drm_gem_dma_object *
drm_gem_dma_create(struct drm_device * ddev,size_t size)1161bb76ff1Sjsg drm_gem_dma_create(struct drm_device *ddev, size_t size)
1171bb76ff1Sjsg {
1181bb76ff1Sjsg 
1191bb76ff1Sjsg 	return drm_gem_dma_create_internal(ddev, size, NULL);
1201bb76ff1Sjsg }
1211bb76ff1Sjsg 
1221bb76ff1Sjsg static void
drm_gem_dma_obj_free(struct drm_gem_dma_object * obj)1231bb76ff1Sjsg drm_gem_dma_obj_free(struct drm_gem_dma_object *obj)
1241bb76ff1Sjsg {
1251bb76ff1Sjsg 
1261bb76ff1Sjsg 	bus_dmamap_unload(obj->dmat, obj->dmamap);
1271bb76ff1Sjsg 	bus_dmamap_destroy(obj->dmat, obj->dmamap);
1281bb76ff1Sjsg 	bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize);
1291bb76ff1Sjsg #ifdef notyet
1301bb76ff1Sjsg 	if (obj->sgt)
1311bb76ff1Sjsg 		drm_prime_sg_free(obj->sgt);
1321bb76ff1Sjsg 	else
1331bb76ff1Sjsg #endif
1341bb76ff1Sjsg 		bus_dmamem_free(obj->dmat, obj->dmasegs, 1);
1351bb76ff1Sjsg 	free(obj, M_DRM, sizeof(*obj));
1361bb76ff1Sjsg }
1371bb76ff1Sjsg 
1381bb76ff1Sjsg void
drm_gem_dma_free_object(struct drm_gem_object * gem_obj)1391bb76ff1Sjsg drm_gem_dma_free_object(struct drm_gem_object *gem_obj)
1401bb76ff1Sjsg {
1411bb76ff1Sjsg 	struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj);
1421bb76ff1Sjsg 
1431bb76ff1Sjsg 	drm_gem_free_mmap_offset(gem_obj);
1441bb76ff1Sjsg 	drm_gem_object_release(gem_obj);
1451bb76ff1Sjsg 	drm_gem_dma_obj_free(obj);
1461bb76ff1Sjsg }
1471bb76ff1Sjsg 
1481bb76ff1Sjsg int
drm_gem_dma_dumb_create_internal(struct drm_file * file_priv,struct drm_device * ddev,struct drm_mode_create_dumb * args)149667382c7Skettenis drm_gem_dma_dumb_create_internal(struct drm_file *file_priv,
150667382c7Skettenis     struct drm_device *ddev, struct drm_mode_create_dumb *args)
1511bb76ff1Sjsg {
1521bb76ff1Sjsg 	struct drm_gem_dma_object *obj;
1531bb76ff1Sjsg 	uint32_t handle;
1541bb76ff1Sjsg 	int error;
1551bb76ff1Sjsg 
1561bb76ff1Sjsg 	args->handle = 0;
1571bb76ff1Sjsg 
1581bb76ff1Sjsg 	obj = drm_gem_dma_create(ddev, args->size);
1591bb76ff1Sjsg 	if (obj == NULL)
1601bb76ff1Sjsg 		return -ENOMEM;
1611bb76ff1Sjsg 
1621bb76ff1Sjsg 	error = drm_gem_handle_create(file_priv, &obj->base, &handle);
1631bb76ff1Sjsg 	drm_gem_object_put(&obj->base);
1641bb76ff1Sjsg 	if (error) {
1651bb76ff1Sjsg 		drm_gem_dma_obj_free(obj);
1661bb76ff1Sjsg 		return error;
1671bb76ff1Sjsg 	}
1681bb76ff1Sjsg 
1691bb76ff1Sjsg 	args->handle = handle;
1701bb76ff1Sjsg 
1711bb76ff1Sjsg 	return 0;
1721bb76ff1Sjsg }
1731bb76ff1Sjsg 
1741bb76ff1Sjsg int
drm_gem_dma_dumb_create(struct drm_file * file_priv,struct drm_device * ddev,struct drm_mode_create_dumb * args)175667382c7Skettenis drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_device *ddev,
176667382c7Skettenis     struct drm_mode_create_dumb *args)
177667382c7Skettenis {
178667382c7Skettenis 	args->pitch = args->width * ((args->bpp + 7) / 8);
179667382c7Skettenis 	args->size = args->pitch * args->height;
180667382c7Skettenis 	args->size = roundup(args->size, PAGE_SIZE);
181667382c7Skettenis 
182667382c7Skettenis 	return drm_gem_dma_dumb_create_internal(file_priv, ddev, args);
183667382c7Skettenis }
184667382c7Skettenis 
185667382c7Skettenis int
drm_gem_dma_fault(struct drm_gem_object * gem_obj,struct uvm_faultinfo * ufi,off_t offset,vaddr_t vaddr,vm_page_t * pps,int npages,int centeridx,vm_prot_t access_type,int flags)1861bb76ff1Sjsg drm_gem_dma_fault(struct drm_gem_object *gem_obj, struct uvm_faultinfo *ufi,
1871bb76ff1Sjsg     off_t offset, vaddr_t vaddr, vm_page_t *pps, int npages, int centeridx,
1881bb76ff1Sjsg     vm_prot_t access_type, int flags)
1891bb76ff1Sjsg {
1901bb76ff1Sjsg 	struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj);
1911bb76ff1Sjsg 	struct uvm_object *uobj = &obj->base.uobj;
1921bb76ff1Sjsg 	paddr_t paddr;
1931bb76ff1Sjsg 	int lcv, retval;
1941bb76ff1Sjsg 	vm_prot_t mapprot;
1951bb76ff1Sjsg 
1961bb76ff1Sjsg 	offset -= drm_vma_node_offset_addr(&obj->base.vma_node);
1971bb76ff1Sjsg 	mapprot = ufi->entry->protection;
1981bb76ff1Sjsg 
1991bb76ff1Sjsg 	retval = 0;
2001bb76ff1Sjsg 	for (lcv = 0; lcv < npages; lcv++, offset += PAGE_SIZE,
2011bb76ff1Sjsg 	    vaddr += PAGE_SIZE) {
2021bb76ff1Sjsg 		if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx)
2031bb76ff1Sjsg 			continue;
2041bb76ff1Sjsg 
2051bb76ff1Sjsg 		if (pps[lcv] == PGO_DONTCARE)
2061bb76ff1Sjsg 			continue;
2071bb76ff1Sjsg 
2081bb76ff1Sjsg 		paddr = bus_dmamem_mmap(obj->dmat, obj->dmasegs, 1,
2091bb76ff1Sjsg 		    offset, access_type, BUS_DMA_NOCACHE);
2101bb76ff1Sjsg 		if (paddr == -1) {
2111bb76ff1Sjsg 			retval = VM_PAGER_BAD;
2121bb76ff1Sjsg 			break;
2131bb76ff1Sjsg 		}
2141bb76ff1Sjsg 
2151bb76ff1Sjsg 		if (pmap_enter(ufi->orig_map->pmap, vaddr, paddr,
2161bb76ff1Sjsg 		    mapprot, PMAP_CANFAIL | mapprot) != 0) {
2171bb76ff1Sjsg 			pmap_update(ufi->orig_map->pmap);
2181bb76ff1Sjsg 			uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap,
2191bb76ff1Sjsg 			    uobj);
2201bb76ff1Sjsg 			uvm_wait("drm_gem_dma_fault");
2211bb76ff1Sjsg 			return VM_PAGER_REFAULT;
2221bb76ff1Sjsg 		}
2231bb76ff1Sjsg 	}
2241bb76ff1Sjsg 
2251bb76ff1Sjsg 	pmap_update(ufi->orig_map->pmap);
2261bb76ff1Sjsg 	uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj);
2271bb76ff1Sjsg 
2281bb76ff1Sjsg 	return retval;
2291bb76ff1Sjsg }
2301bb76ff1Sjsg 
2311bb76ff1Sjsg struct sg_table *
drm_gem_dma_get_sg_table(struct drm_gem_object * gem_obj)2321bb76ff1Sjsg drm_gem_dma_get_sg_table(struct drm_gem_object *gem_obj)
2331bb76ff1Sjsg {
2341bb76ff1Sjsg 	return NULL;
2351bb76ff1Sjsg #ifdef notyet
236*f005ef32Sjsg 	struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj);
237*f005ef32Sjsg 
2381bb76ff1Sjsg 	return drm_prime_bus_dmamem_to_sg(obj->dmat, obj->dmasegs, 1);
2391bb76ff1Sjsg #endif
2401bb76ff1Sjsg }
2411bb76ff1Sjsg 
2421bb76ff1Sjsg struct drm_gem_object *
drm_gem_dma_prime_import_sg_table(struct drm_device * ddev,struct dma_buf_attachment * attach,struct sg_table * sgt)2431bb76ff1Sjsg drm_gem_dma_prime_import_sg_table(struct drm_device *ddev,
2441bb76ff1Sjsg     struct dma_buf_attachment *attach, struct sg_table *sgt)
2451bb76ff1Sjsg {
2461bb76ff1Sjsg 	return NULL;
2471bb76ff1Sjsg #ifdef notyet
2481bb76ff1Sjsg 	size_t size = drm_prime_sg_size(sgt);
2491bb76ff1Sjsg 	struct drm_gem_dma_object *obj;
2501bb76ff1Sjsg 
2511bb76ff1Sjsg 	obj = drm_gem_dma_create_internal(ddev, size, sgt);
2521bb76ff1Sjsg 	if (obj == NULL)
2531bb76ff1Sjsg 		return ERR_PTR(-ENOMEM);
2541bb76ff1Sjsg 
2551bb76ff1Sjsg 	return &obj->base;
2561bb76ff1Sjsg #endif
2571bb76ff1Sjsg }
2581bb76ff1Sjsg 
2591bb76ff1Sjsg int
drm_gem_dma_vmap(struct drm_gem_object * gem_obj,struct iosys_map * map)2601bb76ff1Sjsg drm_gem_dma_vmap(struct drm_gem_object *gem_obj, struct iosys_map *map)
2611bb76ff1Sjsg {
2621bb76ff1Sjsg 	struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj);
2631bb76ff1Sjsg 
2641bb76ff1Sjsg 	iosys_map_set_vaddr(map, obj->vaddr);
2651bb76ff1Sjsg 
2661bb76ff1Sjsg 	return 0;
2671bb76ff1Sjsg }
268