17a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/************************************************************************** 27a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 37a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Copyright 2010 Pauli Nieminen. 47a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * All Rights Reserved. 57a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 67a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Permission is hereby granted, free of charge, to any person obtaining a 77a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * copy of this software and associated documentation files (the 87a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * "Software"), to deal in the Software without restriction, including 97a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * without limitation the rights to use, copy, modify, merge, publish, 107a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * distribute, sub license, and/or sell copies of the Software, and to 117a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * permit persons to whom the Software is furnished to do so, subject to 127a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * the following conditions: 137a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 147a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * The above copyright notice and this permission notice (including the 157a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * next paragraph) shall be included in all copies or substantial portions 167a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * of the Software. 177a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 187a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 197a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 217a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 227a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 237a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 247a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * USE OR OTHER DEALINGS IN THE SOFTWARE. 257a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 267a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 277a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen **************************************************************************/ 287a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/* 297a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Multipart buffer for coping data which is larger than the page size. 307a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 317a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Authors: 327a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Pauli Nieminen <suokkos-at-gmail-dot-com> 337a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen */ 347a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 352d1a8a48ac68a835c42d8a31a02b8158cd599615Paul Gortmaker#include <linux/export.h> 367a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen#include "drm_buffer.h" 377a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 387a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/** 397a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Allocate the drm buffer object. 407a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 417a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * buf: Pointer to a pointer where the object is stored. 427a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * size: The number of bytes to allocate. 437a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen */ 447a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminenint drm_buffer_alloc(struct drm_buffer **buf, int size) 457a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen{ 467a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int nr_pages = size / PAGE_SIZE + 1; 477a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int idx; 487a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 497a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen /* Allocating pointer table to end of structure makes drm_buffer 507a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * variable sized */ 517a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *), 527a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen GFP_KERNEL); 537a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 547a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if (*buf == NULL) { 557a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen DRM_ERROR("Failed to allocate drm buffer object to hold" 567a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen " %d bytes in %d pages.\n", 577a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen size, nr_pages); 587a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return -ENOMEM; 597a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 607a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 617a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen (*buf)->size = size; 627a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 637a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen for (idx = 0; idx < nr_pages; ++idx) { 647a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 657a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen (*buf)->data[idx] = 667a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE), 677a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen GFP_KERNEL); 687a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 697a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 707a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if ((*buf)->data[idx] == NULL) { 717a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen DRM_ERROR("Failed to allocate %dth page for drm" 727a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen " buffer with %d bytes and %d pages.\n", 737a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen idx + 1, size, nr_pages); 747a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen goto error_out; 757a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 767a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 777a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 787a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 797a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return 0; 807a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 817a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminenerror_out: 827a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 837a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen /* Only last element can be null pointer so check for it first. */ 847a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if ((*buf)->data[idx]) 857a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kfree((*buf)->data[idx]); 867a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 877a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen for (--idx; idx >= 0; --idx) 887a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kfree((*buf)->data[idx]); 897a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 907a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kfree(*buf); 917a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return -ENOMEM; 927a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen} 937a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli NieminenEXPORT_SYMBOL(drm_buffer_alloc); 947a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 957a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/** 967a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Copy the user data to the begin of the buffer and reset the processing 977a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * iterator. 987a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 997a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * user_data: A pointer the data that is copied to the buffer. 1007a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * size: The Number of bytes to copy. 1017a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen */ 102d3147e86d71e74c93d361988d9441575da71345eDaniel J Bluemanint drm_buffer_copy_from_user(struct drm_buffer *buf, 103d3147e86d71e74c93d361988d9441575da71345eDaniel J Blueman void __user *user_data, int size) 1047a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen{ 1057a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int nr_pages = size / PAGE_SIZE + 1; 1067a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int idx; 1077a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1087a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if (size > buf->size) { 1097a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen DRM_ERROR("Requesting to copy %d bytes to a drm buffer with" 1107a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen " %d bytes space\n", 1117a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen size, buf->size); 1127a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return -EFAULT; 1137a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 1147a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1157a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen for (idx = 0; idx < nr_pages; ++idx) { 1167a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1177a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if (DRM_COPY_FROM_USER(buf->data[idx], 1187a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen user_data + idx * PAGE_SIZE, 1197a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen min(PAGE_SIZE, size - idx * PAGE_SIZE))) { 1207a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen DRM_ERROR("Failed to copy user data (%p) to drm buffer" 1217a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen " (%p) %dth page.\n", 1227a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen user_data, buf, idx); 1237a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return -EFAULT; 1247a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1257a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 1267a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 1277a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen buf->iterator = 0; 1287a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return 0; 1297a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen} 1307a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli NieminenEXPORT_SYMBOL(drm_buffer_copy_from_user); 1317a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1327a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/** 1337a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Free the drm buffer object 1347a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen */ 1357a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminenvoid drm_buffer_free(struct drm_buffer *buf) 1367a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen{ 1377a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1387a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if (buf != NULL) { 1397a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1407a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int nr_pages = buf->size / PAGE_SIZE + 1; 1417a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int idx; 1427a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen for (idx = 0; idx < nr_pages; ++idx) 1437a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kfree(buf->data[idx]); 1447a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1457a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen kfree(buf); 1467a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 1477a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen} 1487a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli NieminenEXPORT_SYMBOL(drm_buffer_free); 1497a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1507a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen/** 1517a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * Read an object from buffer that may be split to multiple parts. If object 1527a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * is not split function just returns the pointer to object in buffer. But in 1537a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * case of split object data is copied to given stack object that is suplied 1547a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * by caller. 1557a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 1567a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * The processing location of the buffer is also advanced to the next byte 1577a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * after the object. 1587a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * 1597a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * objsize: The size of the objet in bytes. 1607a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen * stack_obj: A pointer to a memory location where object can be copied. 1617a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen */ 1627a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminenvoid *drm_buffer_read_object(struct drm_buffer *buf, 1637a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int objsize, void *stack_obj) 1647a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen{ 1657a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int idx = drm_buffer_index(buf); 1667a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int page = drm_buffer_page(buf); 167d3147e86d71e74c93d361988d9441575da71345eDaniel J Blueman void *obj = NULL; 1687a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1697a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen if (idx + objsize <= PAGE_SIZE) { 1707a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen obj = &buf->data[page][idx]; 1717a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } else { 1727a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen /* The object is split which forces copy to temporary object.*/ 1737a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen int beginsz = PAGE_SIZE - idx; 1747a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen memcpy(stack_obj, &buf->data[page][idx], beginsz); 1757a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1767a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen memcpy(stack_obj + beginsz, &buf->data[page + 1][0], 1777a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen objsize - beginsz); 1787a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1797a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen obj = stack_obj; 1807a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen } 1817a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen 1827a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen drm_buffer_advance(buf, objsize); 1837a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen return obj; 1847a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli Nieminen} 1857a9f0dd9c49425e2b0e39ada4757bc7a38c84873Pauli NieminenEXPORT_SYMBOL(drm_buffer_read_object); 186