mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	 f7ed28e13f
			
		
	
	
		f7ed28e13f
		
	
	
	
	
		
			
			Append _locked to Make clear that these functions should be called with reserved bo's only. While being at it also rename kmap -> vmap. No functional change. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Link: http://patchwork.freedesktop.org/patch/msgid/20210217123213.2199186-6-kraxel@redhat.com
		
			
				
	
	
		
			240 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright 2013 Red Hat Inc.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | |
|  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
|  * OTHER DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Authors: Dave Airlie
 | |
|  *          Alon Levy
 | |
|  */
 | |
| 
 | |
| #include <linux/gfp.h>
 | |
| #include <linux/slab.h>
 | |
| 
 | |
| #include "qxl_drv.h"
 | |
| #include "qxl_object.h"
 | |
| 
 | |
| static int
 | |
| qxl_allocate_chunk(struct qxl_device *qdev,
 | |
| 		   struct qxl_release *release,
 | |
| 		   struct qxl_drm_image *image,
 | |
| 		   unsigned int chunk_size)
 | |
| {
 | |
| 	struct qxl_drm_chunk *chunk;
 | |
| 	int ret;
 | |
| 
 | |
| 	chunk = kmalloc(sizeof(struct qxl_drm_chunk), GFP_KERNEL);
 | |
| 	if (!chunk)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	ret = qxl_alloc_bo_reserved(qdev, release, chunk_size, &chunk->bo);
 | |
| 	if (ret) {
 | |
| 		kfree(chunk);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	list_add_tail(&chunk->head, &image->chunk_list);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| qxl_image_alloc_objects(struct qxl_device *qdev,
 | |
| 			struct qxl_release *release,
 | |
| 			struct qxl_drm_image **image_ptr,
 | |
| 			int height, int stride)
 | |
| {
 | |
| 	struct qxl_drm_image *image;
 | |
| 	int ret;
 | |
| 
 | |
| 	image = kmalloc(sizeof(struct qxl_drm_image), GFP_KERNEL);
 | |
| 	if (!image)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	INIT_LIST_HEAD(&image->chunk_list);
 | |
| 
 | |
| 	ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_image), &image->bo);
 | |
| 	if (ret) {
 | |
| 		kfree(image);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = qxl_allocate_chunk(qdev, release, image, sizeof(struct qxl_data_chunk) + stride * height);
 | |
| 	if (ret) {
 | |
| 		qxl_bo_unref(&image->bo);
 | |
| 		kfree(image);
 | |
| 		return ret;
 | |
| 	}
 | |
| 	*image_ptr = image;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage)
 | |
| {
 | |
| 	struct qxl_drm_chunk *chunk, *tmp;
 | |
| 
 | |
| 	list_for_each_entry_safe(chunk, tmp, &dimage->chunk_list, head) {
 | |
| 		qxl_bo_unref(&chunk->bo);
 | |
| 		kfree(chunk);
 | |
| 	}
 | |
| 
 | |
| 	qxl_bo_unref(&dimage->bo);
 | |
| 	kfree(dimage);
 | |
| }
 | |
| 
 | |
| static int
 | |
| qxl_image_init_helper(struct qxl_device *qdev,
 | |
| 		      struct qxl_release *release,
 | |
| 		      struct qxl_drm_image *dimage,
 | |
| 		      const uint8_t *data,
 | |
| 		      int width, int height,
 | |
| 		      int depth, unsigned int hash,
 | |
| 		      int stride)
 | |
| {
 | |
| 	struct qxl_drm_chunk *drv_chunk;
 | |
| 	struct qxl_image *image;
 | |
| 	struct qxl_data_chunk *chunk;
 | |
| 	int i;
 | |
| 	int chunk_stride;
 | |
| 	int linesize = width * depth / 8;
 | |
| 	struct qxl_bo *chunk_bo, *image_bo;
 | |
| 	void *ptr;
 | |
| 	/* Chunk */
 | |
| 	/* FIXME: Check integer overflow */
 | |
| 	/* TODO: variable number of chunks */
 | |
| 
 | |
| 	drv_chunk = list_first_entry(&dimage->chunk_list, struct qxl_drm_chunk, head);
 | |
| 
 | |
| 	chunk_bo = drv_chunk->bo;
 | |
| 	chunk_stride = stride; /* TODO: should use linesize, but it renders
 | |
| 				  wrong (check the bitmaps are sent correctly
 | |
| 				  first) */
 | |
| 
 | |
| 	ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0);
 | |
| 	chunk = ptr;
 | |
| 	chunk->data_size = height * chunk_stride;
 | |
| 	chunk->prev_chunk = 0;
 | |
| 	chunk->next_chunk = 0;
 | |
| 	qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 | |
| 
 | |
| 	{
 | |
| 		void *k_data, *i_data;
 | |
| 		int remain;
 | |
| 		int page;
 | |
| 		int size;
 | |
| 
 | |
| 		if (stride == linesize && chunk_stride == stride) {
 | |
| 			remain = linesize * height;
 | |
| 			page = 0;
 | |
| 			i_data = (void *)data;
 | |
| 
 | |
| 			while (remain > 0) {
 | |
| 				ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page << PAGE_SHIFT);
 | |
| 
 | |
| 				if (page == 0) {
 | |
| 					chunk = ptr;
 | |
| 					k_data = chunk->data;
 | |
| 					size = PAGE_SIZE - offsetof(struct qxl_data_chunk, data);
 | |
| 				} else {
 | |
| 					k_data = ptr;
 | |
| 					size = PAGE_SIZE;
 | |
| 				}
 | |
| 				size = min(size, remain);
 | |
| 
 | |
| 				memcpy(k_data, i_data, size);
 | |
| 
 | |
| 				qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 | |
| 				i_data += size;
 | |
| 				remain -= size;
 | |
| 				page++;
 | |
| 			}
 | |
| 		} else {
 | |
| 			unsigned int page_base, page_offset, out_offset;
 | |
| 
 | |
| 			for (i = 0 ; i < height ; ++i) {
 | |
| 				i_data = (void *)data + i * stride;
 | |
| 				remain = linesize;
 | |
| 				out_offset = offsetof(struct qxl_data_chunk, data) + i * chunk_stride;
 | |
| 
 | |
| 				while (remain > 0) {
 | |
| 					page_base = out_offset & PAGE_MASK;
 | |
| 					page_offset = offset_in_page(out_offset);
 | |
| 					size = min((int)(PAGE_SIZE - page_offset), remain);
 | |
| 
 | |
| 					ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base);
 | |
| 					k_data = ptr + page_offset;
 | |
| 					memcpy(k_data, i_data, size);
 | |
| 					qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 | |
| 					remain -= size;
 | |
| 					i_data += size;
 | |
| 					out_offset += size;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	qxl_bo_vunmap_locked(chunk_bo);
 | |
| 
 | |
| 	image_bo = dimage->bo;
 | |
| 	ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
 | |
| 	image = ptr;
 | |
| 
 | |
| 	image->descriptor.id = 0;
 | |
| 	image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
 | |
| 
 | |
| 	image->descriptor.flags = 0;
 | |
| 	image->descriptor.width = width;
 | |
| 	image->descriptor.height = height;
 | |
| 
 | |
| 	switch (depth) {
 | |
| 	case 1:
 | |
| 		/* TODO: BE? check by arch? */
 | |
| 		image->u.bitmap.format = SPICE_BITMAP_FMT_1BIT_BE;
 | |
| 		break;
 | |
| 	case 24:
 | |
| 		image->u.bitmap.format = SPICE_BITMAP_FMT_24BIT;
 | |
| 		break;
 | |
| 	case 32:
 | |
| 		image->u.bitmap.format = SPICE_BITMAP_FMT_32BIT;
 | |
| 		break;
 | |
| 	default:
 | |
| 		DRM_ERROR("unsupported image bit depth\n");
 | |
| 		qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 	image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN;
 | |
| 	image->u.bitmap.x = width;
 | |
| 	image->u.bitmap.y = height;
 | |
| 	image->u.bitmap.stride = chunk_stride;
 | |
| 	image->u.bitmap.palette = 0;
 | |
| 	image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0);
 | |
| 
 | |
| 	qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int qxl_image_init(struct qxl_device *qdev,
 | |
| 		     struct qxl_release *release,
 | |
| 		     struct qxl_drm_image *dimage,
 | |
| 		     const uint8_t *data,
 | |
| 		     int x, int y, int width, int height,
 | |
| 		     int depth, int stride)
 | |
| {
 | |
| 	data += y * stride + x * (depth / 8);
 | |
| 	return qxl_image_init_helper(qdev, release, dimage, data,
 | |
| 				       width, height, depth, 0, stride);
 | |
| }
 |