drm_buffer.c revision 254794
119370Spst/************************************************************************** 219370Spst * 3130803Smarcel * Copyright 2010 Pauli Nieminen. 4130803Smarcel * All Rights Reserved. 5130803Smarcel * 698944Sobrien * Permission is hereby granted, free of charge, to any person obtaining a 798944Sobrien * copy of this software and associated documentation files (the 898944Sobrien * "Software"), to deal in the Software without restriction, including 998944Sobrien * without limitation the rights to use, copy, modify, merge, publish, 1019370Spst * distribute, sub license, and/or sell copies of the Software, and to 1198944Sobrien * permit persons to whom the Software is furnished to do so, subject to 1298944Sobrien * the following conditions: 1398944Sobrien * 1498944Sobrien * The above copyright notice and this permission notice (including the 1519370Spst * next paragraph) shall be included in all copies or substantial portions 1698944Sobrien * of the Software. 1798944Sobrien * 1898944Sobrien * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1998944Sobrien * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2019370Spst * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2119370Spst * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2219370Spst * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2319370Spst * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2419370Spst * USE OR OTHER DEALINGS IN THE SOFTWARE. 2519370Spst * 2619370Spst * 2798944Sobrien **************************************************************************/ 2819370Spst/* 2919370Spst * Multipart buffer for coping data which is larger than the page size. 3019370Spst * 3119370Spst * Authors: 3298944Sobrien * Pauli Nieminen <suokkos-at-gmail-dot-com> 3319370Spst */ 34130803Smarcel 3519370Spst#include <sys/cdefs.h> 3619370Spst__FBSDID("$FreeBSD: head/sys/dev/drm2/drm_buffer.c 254794 2013-08-24 16:14:20Z dumbbell $"); 3719370Spst 3819370Spst#include <dev/drm2/drm_buffer.h> 3919370Spst 4019370Spst/** 4119370Spst * Allocate the drm buffer object. 4219370Spst * 4319370Spst * buf: Pointer to a pointer where the object is stored. 4419370Spst * size: The number of bytes to allocate. 4519370Spst */ 4619370Spstint drm_buffer_alloc(struct drm_buffer **buf, int size) 47130803Smarcel{ 4819370Spst int nr_pages = size / PAGE_SIZE + 1; 49130803Smarcel int idx; 5019370Spst 5119370Spst /* Allocating pointer table to end of structure makes drm_buffer 5298944Sobrien * variable sized */ 5319370Spst *buf = malloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *), 5498944Sobrien DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 5519370Spst 5619370Spst if (*buf == NULL) { 5719370Spst DRM_ERROR("Failed to allocate drm buffer object to hold" 5819370Spst " %d bytes in %d pages.\n", 5919370Spst size, nr_pages); 6019370Spst return -ENOMEM; 6119370Spst } 62130803Smarcel 6319370Spst (*buf)->size = size; 6419370Spst 65130803Smarcel for (idx = 0; idx < nr_pages; ++idx) { 6619370Spst 6719370Spst (*buf)->data[idx] = 6819370Spst malloc(min(PAGE_SIZE, size - idx * PAGE_SIZE), 6919370Spst DRM_MEM_DRIVER, M_WAITOK); 7098944Sobrien 7119370Spst 7219370Spst if ((*buf)->data[idx] == NULL) { 7319370Spst DRM_ERROR("Failed to allocate %dth page for drm" 7419370Spst " buffer with %d bytes and %d pages.\n", 7598944Sobrien idx + 1, size, nr_pages); 7619370Spst goto error_out; 7719370Spst } 7819370Spst 7919370Spst } 8019370Spst 8119370Spst return 0; 8219370Spst 83130803Smarcelerror_out: 84130803Smarcel 8519370Spst /* Only last element can be null pointer so check for it first. */ 8619370Spst if ((*buf)->data[idx]) 8719370Spst free((*buf)->data[idx], DRM_MEM_DRIVER); 8819370Spst 8919370Spst for (--idx; idx >= 0; --idx) 9019370Spst free((*buf)->data[idx], DRM_MEM_DRIVER); 9119370Spst 9219370Spst free(*buf, DRM_MEM_DRIVER); 9319370Spst return -ENOMEM; 9498944Sobrien} 9519370Spst 9619370Spst/** 9719370Spst * Copy the user data to the begin of the buffer and reset the processing 9819370Spst * iterator. 9919370Spst * 10019370Spst * user_data: A pointer the data that is copied to the buffer. 10119370Spst * size: The Number of bytes to copy. 10298944Sobrien */ 10319370Spstint drm_buffer_copy_from_user(struct drm_buffer *buf, 104130803Smarcel void __user *user_data, int size) 105130803Smarcel{ 106130803Smarcel int nr_pages = size / PAGE_SIZE + 1; 10719370Spst int idx; 10819370Spst 109130803Smarcel if (size > buf->size) { 11019370Spst DRM_ERROR("Requesting to copy %d bytes to a drm buffer with" 11119370Spst " %d bytes space\n", 11219370Spst size, buf->size); 11319370Spst return -EFAULT; 11419370Spst } 11519370Spst 11619370Spst for (idx = 0; idx < nr_pages; ++idx) { 11719370Spst 11898944Sobrien if (DRM_COPY_FROM_USER(buf->data[idx], 11919370Spst (char *)user_data + idx * PAGE_SIZE, 120130803Smarcel min(PAGE_SIZE, size - idx * PAGE_SIZE))) { 121130803Smarcel DRM_ERROR("Failed to copy user data (%p) to drm buffer" 122130803Smarcel " (%p) %dth page.\n", 123130803Smarcel user_data, buf, idx); 12419370Spst return -EFAULT; 12519370Spst 126130803Smarcel } 12719370Spst } 12819370Spst buf->iterator = 0; 12919370Spst return 0; 13019370Spst} 13119370Spst 13219370Spst/** 13319370Spst * Free the drm buffer object 13498944Sobrien */ 13519370Spstvoid drm_buffer_free(struct drm_buffer *buf) 13619370Spst{ 13719370Spst 13819370Spst if (buf != NULL) { 13919370Spst 14019370Spst int nr_pages = buf->size / PAGE_SIZE + 1; 14198944Sobrien int idx; 14219370Spst for (idx = 0; idx < nr_pages; ++idx) 14319370Spst free(buf->data[idx], DRM_MEM_DRIVER); 14419370Spst 14519370Spst free(buf, DRM_MEM_DRIVER); 14619370Spst } 14719370Spst} 14819370Spst 14919370Spst/** 15019370Spst * Read an object from buffer that may be split to multiple parts. If object 15119370Spst * is not split function just returns the pointer to object in buffer. But in 15219370Spst * case of split object data is copied to given stack object that is suplied 15319370Spst * by caller. 15419370Spst * 15519370Spst * The processing location of the buffer is also advanced to the next byte 15619370Spst * after the object. 15719370Spst * 15819370Spst * objsize: The size of the objet in bytes. 15919370Spst * stack_obj: A pointer to a memory location where object can be copied. 16019370Spst */ 16119370Spstvoid *drm_buffer_read_object(struct drm_buffer *buf, 16219370Spst int objsize, void *stack_obj) 16319370Spst{ 16419370Spst int idx = drm_buffer_index(buf); 16598944Sobrien int page = drm_buffer_page(buf); 16619370Spst void *obj = NULL; 167130803Smarcel 168130803Smarcel if (idx + objsize <= PAGE_SIZE) { 169130803Smarcel obj = &buf->data[page][idx]; 17019370Spst } else { 17119370Spst /* The object is split which forces copy to temporary object.*/ 17219370Spst int beginsz = PAGE_SIZE - idx; 173130803Smarcel memcpy(stack_obj, &buf->data[page][idx], beginsz); 17419370Spst 17598944Sobrien memcpy((char *)stack_obj + beginsz, &buf->data[page + 1][0], 17619370Spst objsize - beginsz); 17719370Spst 17819370Spst obj = stack_obj; 17919370Spst } 18019370Spst 18119370Spst drm_buffer_advance(buf, objsize); 18219370Spst return obj; 18319370Spst} 18419370Spst