1*592ffb21SWarner Losh /************************************************************************** 2*592ffb21SWarner Losh * 3*592ffb21SWarner Losh * Copyright 2010 Pauli Nieminen. 4*592ffb21SWarner Losh * All Rights Reserved. 5*592ffb21SWarner Losh * 6*592ffb21SWarner Losh * Permission is hereby granted, free of charge, to any person obtaining a 7*592ffb21SWarner Losh * copy of this software and associated documentation files (the 8*592ffb21SWarner Losh * "Software"), to deal in the Software without restriction, including 9*592ffb21SWarner Losh * without limitation the rights to use, copy, modify, merge, publish, 10*592ffb21SWarner Losh * distribute, sub license, and/or sell copies of the Software, and to 11*592ffb21SWarner Losh * permit persons to whom the Software is furnished to do so, subject to 12*592ffb21SWarner Losh * the following conditions: 13*592ffb21SWarner Losh * 14*592ffb21SWarner Losh * The above copyright notice and this permission notice (including the 15*592ffb21SWarner Losh * next paragraph) shall be included in all copies or substantial portions 16*592ffb21SWarner Losh * of the Software. 17*592ffb21SWarner Losh * 18*592ffb21SWarner Losh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*592ffb21SWarner Losh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*592ffb21SWarner Losh * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21*592ffb21SWarner Losh * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22*592ffb21SWarner Losh * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23*592ffb21SWarner Losh * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24*592ffb21SWarner Losh * USE OR OTHER DEALINGS IN THE SOFTWARE. 25*592ffb21SWarner Losh * 26*592ffb21SWarner Losh * 27*592ffb21SWarner Losh **************************************************************************/ 28*592ffb21SWarner Losh /* 29*592ffb21SWarner Losh * Multipart buffer for coping data which is larger than the page size. 30*592ffb21SWarner Losh * 31*592ffb21SWarner Losh * Authors: 32*592ffb21SWarner Losh * Pauli Nieminen <suokkos-at-gmail-dot-com> 33*592ffb21SWarner Losh */ 34*592ffb21SWarner Losh 35*592ffb21SWarner Losh #include <sys/cdefs.h> 36*592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 37*592ffb21SWarner Losh 38*592ffb21SWarner Losh #include <dev/drm2/drm_buffer.h> 39*592ffb21SWarner Losh 40*592ffb21SWarner Losh /** 41*592ffb21SWarner Losh * Allocate the drm buffer object. 42*592ffb21SWarner Losh * 43*592ffb21SWarner Losh * buf: Pointer to a pointer where the object is stored. 44*592ffb21SWarner Losh * size: The number of bytes to allocate. 45*592ffb21SWarner Losh */ 46*592ffb21SWarner Losh int drm_buffer_alloc(struct drm_buffer **buf, int size) 47*592ffb21SWarner Losh { 48*592ffb21SWarner Losh int nr_pages = size / PAGE_SIZE + 1; 49*592ffb21SWarner Losh int idx; 50*592ffb21SWarner Losh 51*592ffb21SWarner Losh /* Allocating pointer table to end of structure makes drm_buffer 52*592ffb21SWarner Losh * variable sized */ 53*592ffb21SWarner Losh *buf = malloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *), 54*592ffb21SWarner Losh DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 55*592ffb21SWarner Losh 56*592ffb21SWarner Losh if (*buf == NULL) { 57*592ffb21SWarner Losh DRM_ERROR("Failed to allocate drm buffer object to hold" 58*592ffb21SWarner Losh " %d bytes in %d pages.\n", 59*592ffb21SWarner Losh size, nr_pages); 60*592ffb21SWarner Losh return -ENOMEM; 61*592ffb21SWarner Losh } 62*592ffb21SWarner Losh 63*592ffb21SWarner Losh (*buf)->size = size; 64*592ffb21SWarner Losh 65*592ffb21SWarner Losh for (idx = 0; idx < nr_pages; ++idx) { 66*592ffb21SWarner Losh 67*592ffb21SWarner Losh (*buf)->data[idx] = 68*592ffb21SWarner Losh malloc(min(PAGE_SIZE, size - idx * PAGE_SIZE), 69*592ffb21SWarner Losh DRM_MEM_DRIVER, M_WAITOK); 70*592ffb21SWarner Losh 71*592ffb21SWarner Losh 72*592ffb21SWarner Losh if ((*buf)->data[idx] == NULL) { 73*592ffb21SWarner Losh DRM_ERROR("Failed to allocate %dth page for drm" 74*592ffb21SWarner Losh " buffer with %d bytes and %d pages.\n", 75*592ffb21SWarner Losh idx + 1, size, nr_pages); 76*592ffb21SWarner Losh goto error_out; 77*592ffb21SWarner Losh } 78*592ffb21SWarner Losh 79*592ffb21SWarner Losh } 80*592ffb21SWarner Losh 81*592ffb21SWarner Losh return 0; 82*592ffb21SWarner Losh 83*592ffb21SWarner Losh error_out: 84*592ffb21SWarner Losh 85*592ffb21SWarner Losh /* Only last element can be null pointer so check for it first. */ 86*592ffb21SWarner Losh if ((*buf)->data[idx]) 87*592ffb21SWarner Losh free((*buf)->data[idx], DRM_MEM_DRIVER); 88*592ffb21SWarner Losh 89*592ffb21SWarner Losh for (--idx; idx >= 0; --idx) 90*592ffb21SWarner Losh free((*buf)->data[idx], DRM_MEM_DRIVER); 91*592ffb21SWarner Losh 92*592ffb21SWarner Losh free(*buf, DRM_MEM_DRIVER); 93*592ffb21SWarner Losh return -ENOMEM; 94*592ffb21SWarner Losh } 95*592ffb21SWarner Losh EXPORT_SYMBOL(drm_buffer_alloc); 96*592ffb21SWarner Losh 97*592ffb21SWarner Losh /** 98*592ffb21SWarner Losh * Copy the user data to the begin of the buffer and reset the processing 99*592ffb21SWarner Losh * iterator. 100*592ffb21SWarner Losh * 101*592ffb21SWarner Losh * user_data: A pointer the data that is copied to the buffer. 102*592ffb21SWarner Losh * size: The Number of bytes to copy. 103*592ffb21SWarner Losh */ 104*592ffb21SWarner Losh int drm_buffer_copy_from_user(struct drm_buffer *buf, 105*592ffb21SWarner Losh void __user *user_data, int size) 106*592ffb21SWarner Losh { 107*592ffb21SWarner Losh int nr_pages = size / PAGE_SIZE + 1; 108*592ffb21SWarner Losh int idx; 109*592ffb21SWarner Losh 110*592ffb21SWarner Losh if (size > buf->size) { 111*592ffb21SWarner Losh DRM_ERROR("Requesting to copy %d bytes to a drm buffer with" 112*592ffb21SWarner Losh " %d bytes space\n", 113*592ffb21SWarner Losh size, buf->size); 114*592ffb21SWarner Losh return -EFAULT; 115*592ffb21SWarner Losh } 116*592ffb21SWarner Losh 117*592ffb21SWarner Losh for (idx = 0; idx < nr_pages; ++idx) { 118*592ffb21SWarner Losh 119*592ffb21SWarner Losh if (DRM_COPY_FROM_USER(buf->data[idx], 120*592ffb21SWarner Losh (char *)user_data + idx * PAGE_SIZE, 121*592ffb21SWarner Losh min(PAGE_SIZE, size - idx * PAGE_SIZE))) { 122*592ffb21SWarner Losh DRM_ERROR("Failed to copy user data (%p) to drm buffer" 123*592ffb21SWarner Losh " (%p) %dth page.\n", 124*592ffb21SWarner Losh user_data, buf, idx); 125*592ffb21SWarner Losh return -EFAULT; 126*592ffb21SWarner Losh 127*592ffb21SWarner Losh } 128*592ffb21SWarner Losh } 129*592ffb21SWarner Losh buf->iterator = 0; 130*592ffb21SWarner Losh return 0; 131*592ffb21SWarner Losh } 132*592ffb21SWarner Losh EXPORT_SYMBOL(drm_buffer_copy_from_user); 133*592ffb21SWarner Losh 134*592ffb21SWarner Losh /** 135*592ffb21SWarner Losh * Free the drm buffer object 136*592ffb21SWarner Losh */ 137*592ffb21SWarner Losh void drm_buffer_free(struct drm_buffer *buf) 138*592ffb21SWarner Losh { 139*592ffb21SWarner Losh 140*592ffb21SWarner Losh if (buf != NULL) { 141*592ffb21SWarner Losh 142*592ffb21SWarner Losh int nr_pages = buf->size / PAGE_SIZE + 1; 143*592ffb21SWarner Losh int idx; 144*592ffb21SWarner Losh for (idx = 0; idx < nr_pages; ++idx) 145*592ffb21SWarner Losh free(buf->data[idx], DRM_MEM_DRIVER); 146*592ffb21SWarner Losh 147*592ffb21SWarner Losh free(buf, DRM_MEM_DRIVER); 148*592ffb21SWarner Losh } 149*592ffb21SWarner Losh } 150*592ffb21SWarner Losh EXPORT_SYMBOL(drm_buffer_free); 151*592ffb21SWarner Losh 152*592ffb21SWarner Losh /** 153*592ffb21SWarner Losh * Read an object from buffer that may be split to multiple parts. If object 154*592ffb21SWarner Losh * is not split function just returns the pointer to object in buffer. But in 155*592ffb21SWarner Losh * case of split object data is copied to given stack object that is suplied 156*592ffb21SWarner Losh * by caller. 157*592ffb21SWarner Losh * 158*592ffb21SWarner Losh * The processing location of the buffer is also advanced to the next byte 159*592ffb21SWarner Losh * after the object. 160*592ffb21SWarner Losh * 161*592ffb21SWarner Losh * objsize: The size of the objet in bytes. 162*592ffb21SWarner Losh * stack_obj: A pointer to a memory location where object can be copied. 163*592ffb21SWarner Losh */ 164*592ffb21SWarner Losh void *drm_buffer_read_object(struct drm_buffer *buf, 165*592ffb21SWarner Losh int objsize, void *stack_obj) 166*592ffb21SWarner Losh { 167*592ffb21SWarner Losh int idx = drm_buffer_index(buf); 168*592ffb21SWarner Losh int page = drm_buffer_page(buf); 169*592ffb21SWarner Losh void *obj = NULL; 170*592ffb21SWarner Losh 171*592ffb21SWarner Losh if (idx + objsize <= PAGE_SIZE) { 172*592ffb21SWarner Losh obj = &buf->data[page][idx]; 173*592ffb21SWarner Losh } else { 174*592ffb21SWarner Losh /* The object is split which forces copy to temporary object.*/ 175*592ffb21SWarner Losh int beginsz = PAGE_SIZE - idx; 176*592ffb21SWarner Losh memcpy(stack_obj, &buf->data[page][idx], beginsz); 177*592ffb21SWarner Losh 178*592ffb21SWarner Losh memcpy((char *)stack_obj + beginsz, &buf->data[page + 1][0], 179*592ffb21SWarner Losh objsize - beginsz); 180*592ffb21SWarner Losh 181*592ffb21SWarner Losh obj = stack_obj; 182*592ffb21SWarner Losh } 183*592ffb21SWarner Losh 184*592ffb21SWarner Losh drm_buffer_advance(buf, objsize); 185*592ffb21SWarner Losh return obj; 186*592ffb21SWarner Losh } 187*592ffb21SWarner Losh EXPORT_SYMBOL(drm_buffer_read_object); 188