1 1.1 riastrad /* $NetBSD: vmwgfx_blit.c,v 1.2 2021/12/18 23:45:45 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad // SPDX-License-Identifier: GPL-2.0 OR MIT 4 1.1 riastrad /************************************************************************** 5 1.1 riastrad * 6 1.1 riastrad * Copyright 2017 VMware, Inc., Palo Alto, CA., USA 7 1.1 riastrad * All Rights Reserved. 8 1.1 riastrad * 9 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 10 1.1 riastrad * copy of this software and associated documentation files (the 11 1.1 riastrad * "Software"), to deal in the Software without restriction, including 12 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 13 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 14 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 15 1.1 riastrad * the following conditions: 16 1.1 riastrad * 17 1.1 riastrad * The above copyright notice and this permission notice (including the 18 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 19 1.1 riastrad * of the Software. 20 1.1 riastrad * 21 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 24 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 25 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 26 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 27 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 28 1.1 riastrad * 29 1.1 riastrad **************************************************************************/ 30 1.1 riastrad 31 1.1 riastrad #include <sys/cdefs.h> 32 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_blit.c,v 1.2 2021/12/18 23:45:45 riastradh Exp $"); 33 1.1 riastrad 34 1.1 riastrad #include "vmwgfx_drv.h" 35 1.1 riastrad 36 1.1 riastrad /* 37 1.1 riastrad * Template that implements find_first_diff() for a generic 38 1.1 riastrad * unsigned integer type. @size and return value are in bytes. 39 1.1 riastrad */ 40 1.1 riastrad #define VMW_FIND_FIRST_DIFF(_type) \ 41 1.1 riastrad static size_t vmw_find_first_diff_ ## _type \ 42 1.1 riastrad (const _type * dst, const _type * src, size_t size)\ 43 1.1 riastrad { \ 44 1.1 riastrad size_t i; \ 45 1.1 riastrad \ 46 1.1 riastrad for (i = 0; i < size; i += sizeof(_type)) { \ 47 1.1 riastrad if (*dst++ != *src++) \ 48 1.1 riastrad break; \ 49 1.1 riastrad } \ 50 1.1 riastrad \ 51 1.1 riastrad return i; \ 52 1.1 riastrad } 53 1.1 riastrad 54 1.1 riastrad 55 1.1 riastrad /* 56 1.1 riastrad * Template that implements find_last_diff() for a generic 57 1.1 riastrad * unsigned integer type. Pointers point to the item following the 58 1.1 riastrad * *end* of the area to be examined. @size and return value are in 59 1.1 riastrad * bytes. 60 1.1 riastrad */ 61 1.1 riastrad #define VMW_FIND_LAST_DIFF(_type) \ 62 1.1 riastrad static ssize_t vmw_find_last_diff_ ## _type( \ 63 1.1 riastrad const _type * dst, const _type * src, size_t size) \ 64 1.1 riastrad { \ 65 1.1 riastrad while (size) { \ 66 1.1 riastrad if (*--dst != *--src) \ 67 1.1 riastrad break; \ 68 1.1 riastrad \ 69 1.1 riastrad size -= sizeof(_type); \ 70 1.1 riastrad } \ 71 1.1 riastrad return size; \ 72 1.1 riastrad } 73 1.1 riastrad 74 1.1 riastrad 75 1.1 riastrad /* 76 1.1 riastrad * Instantiate find diff functions for relevant unsigned integer sizes, 77 1.1 riastrad * assuming that wider integers are faster (including aligning) up to the 78 1.1 riastrad * architecture native width, which is assumed to be 32 bit unless 79 1.1 riastrad * CONFIG_64BIT is defined. 80 1.1 riastrad */ 81 1.1 riastrad VMW_FIND_FIRST_DIFF(u8); 82 1.1 riastrad VMW_FIND_LAST_DIFF(u8); 83 1.1 riastrad 84 1.1 riastrad VMW_FIND_FIRST_DIFF(u16); 85 1.1 riastrad VMW_FIND_LAST_DIFF(u16); 86 1.1 riastrad 87 1.1 riastrad VMW_FIND_FIRST_DIFF(u32); 88 1.1 riastrad VMW_FIND_LAST_DIFF(u32); 89 1.1 riastrad 90 1.1 riastrad #ifdef CONFIG_64BIT 91 1.1 riastrad VMW_FIND_FIRST_DIFF(u64); 92 1.1 riastrad VMW_FIND_LAST_DIFF(u64); 93 1.1 riastrad #endif 94 1.1 riastrad 95 1.1 riastrad 96 1.1 riastrad /* We use size aligned copies. This computes (addr - align(addr)) */ 97 1.1 riastrad #define SPILL(_var, _type) ((unsigned long) _var & (sizeof(_type) - 1)) 98 1.1 riastrad 99 1.1 riastrad 100 1.1 riastrad /* 101 1.1 riastrad * Template to compute find_first_diff() for a certain integer type 102 1.1 riastrad * including a head copy for alignment, and adjustment of parameters 103 1.1 riastrad * for tail find or increased resolution find using an unsigned integer find 104 1.1 riastrad * of smaller width. If finding is complete, and resolution is sufficient, 105 1.1 riastrad * the macro executes a return statement. Otherwise it falls through. 106 1.1 riastrad */ 107 1.1 riastrad #define VMW_TRY_FIND_FIRST_DIFF(_type) \ 108 1.1 riastrad do { \ 109 1.1 riastrad unsigned int spill = SPILL(dst, _type); \ 110 1.1 riastrad size_t diff_offs; \ 111 1.1 riastrad \ 112 1.1 riastrad if (spill && spill == SPILL(src, _type) && \ 113 1.1 riastrad sizeof(_type) - spill <= size) { \ 114 1.1 riastrad spill = sizeof(_type) - spill; \ 115 1.1 riastrad diff_offs = vmw_find_first_diff_u8(dst, src, spill); \ 116 1.1 riastrad if (diff_offs < spill) \ 117 1.1 riastrad return round_down(offset + diff_offs, granularity); \ 118 1.1 riastrad \ 119 1.1 riastrad dst += spill; \ 120 1.1 riastrad src += spill; \ 121 1.1 riastrad size -= spill; \ 122 1.1 riastrad offset += spill; \ 123 1.1 riastrad spill = 0; \ 124 1.1 riastrad } \ 125 1.1 riastrad if (!spill && !SPILL(src, _type)) { \ 126 1.1 riastrad size_t to_copy = size & ~(sizeof(_type) - 1); \ 127 1.1 riastrad \ 128 1.1 riastrad diff_offs = vmw_find_first_diff_ ## _type \ 129 1.1 riastrad ((_type *) dst, (_type *) src, to_copy); \ 130 1.1 riastrad if (diff_offs >= size || granularity == sizeof(_type)) \ 131 1.1 riastrad return (offset + diff_offs); \ 132 1.1 riastrad \ 133 1.1 riastrad dst += diff_offs; \ 134 1.1 riastrad src += diff_offs; \ 135 1.1 riastrad size -= diff_offs; \ 136 1.1 riastrad offset += diff_offs; \ 137 1.1 riastrad } \ 138 1.1 riastrad } while (0) \ 139 1.1 riastrad 140 1.1 riastrad 141 1.1 riastrad /** 142 1.1 riastrad * vmw_find_first_diff - find the first difference between dst and src 143 1.1 riastrad * 144 1.1 riastrad * @dst: The destination address 145 1.1 riastrad * @src: The source address 146 1.1 riastrad * @size: Number of bytes to compare 147 1.1 riastrad * @granularity: The granularity needed for the return value in bytes. 148 1.1 riastrad * return: The offset from find start where the first difference was 149 1.1 riastrad * encountered in bytes. If no difference was found, the function returns 150 1.1 riastrad * a value >= @size. 151 1.1 riastrad */ 152 1.1 riastrad static size_t vmw_find_first_diff(const u8 *dst, const u8 *src, size_t size, 153 1.1 riastrad size_t granularity) 154 1.1 riastrad { 155 1.1 riastrad size_t offset = 0; 156 1.1 riastrad 157 1.1 riastrad /* 158 1.1 riastrad * Try finding with large integers if alignment allows, or we can 159 1.1 riastrad * fix it. Fall through if we need better resolution or alignment 160 1.1 riastrad * was bad. 161 1.1 riastrad */ 162 1.1 riastrad #ifdef CONFIG_64BIT 163 1.1 riastrad VMW_TRY_FIND_FIRST_DIFF(u64); 164 1.1 riastrad #endif 165 1.1 riastrad VMW_TRY_FIND_FIRST_DIFF(u32); 166 1.1 riastrad VMW_TRY_FIND_FIRST_DIFF(u16); 167 1.1 riastrad 168 1.1 riastrad return round_down(offset + vmw_find_first_diff_u8(dst, src, size), 169 1.1 riastrad granularity); 170 1.1 riastrad } 171 1.1 riastrad 172 1.1 riastrad 173 1.1 riastrad /* 174 1.1 riastrad * Template to compute find_last_diff() for a certain integer type 175 1.1 riastrad * including a tail copy for alignment, and adjustment of parameters 176 1.1 riastrad * for head find or increased resolution find using an unsigned integer find 177 1.1 riastrad * of smaller width. If finding is complete, and resolution is sufficient, 178 1.1 riastrad * the macro executes a return statement. Otherwise it falls through. 179 1.1 riastrad */ 180 1.1 riastrad #define VMW_TRY_FIND_LAST_DIFF(_type) \ 181 1.1 riastrad do { \ 182 1.1 riastrad unsigned int spill = SPILL(dst, _type); \ 183 1.1 riastrad ssize_t location; \ 184 1.1 riastrad ssize_t diff_offs; \ 185 1.1 riastrad \ 186 1.1 riastrad if (spill && spill <= size && spill == SPILL(src, _type)) { \ 187 1.1 riastrad diff_offs = vmw_find_last_diff_u8(dst, src, spill); \ 188 1.1 riastrad if (diff_offs) { \ 189 1.1 riastrad location = size - spill + diff_offs - 1; \ 190 1.1 riastrad return round_down(location, granularity); \ 191 1.1 riastrad } \ 192 1.1 riastrad \ 193 1.1 riastrad dst -= spill; \ 194 1.1 riastrad src -= spill; \ 195 1.1 riastrad size -= spill; \ 196 1.1 riastrad spill = 0; \ 197 1.1 riastrad } \ 198 1.1 riastrad if (!spill && !SPILL(src, _type)) { \ 199 1.1 riastrad size_t to_copy = round_down(size, sizeof(_type)); \ 200 1.1 riastrad \ 201 1.1 riastrad diff_offs = vmw_find_last_diff_ ## _type \ 202 1.1 riastrad ((_type *) dst, (_type *) src, to_copy); \ 203 1.1 riastrad location = size - to_copy + diff_offs - sizeof(_type); \ 204 1.1 riastrad if (location < 0 || granularity == sizeof(_type)) \ 205 1.1 riastrad return location; \ 206 1.1 riastrad \ 207 1.1 riastrad dst -= to_copy - diff_offs; \ 208 1.1 riastrad src -= to_copy - diff_offs; \ 209 1.1 riastrad size -= to_copy - diff_offs; \ 210 1.1 riastrad } \ 211 1.1 riastrad } while (0) 212 1.1 riastrad 213 1.1 riastrad 214 1.1 riastrad /** 215 1.1 riastrad * vmw_find_last_diff - find the last difference between dst and src 216 1.1 riastrad * 217 1.1 riastrad * @dst: The destination address 218 1.1 riastrad * @src: The source address 219 1.1 riastrad * @size: Number of bytes to compare 220 1.1 riastrad * @granularity: The granularity needed for the return value in bytes. 221 1.1 riastrad * return: The offset from find start where the last difference was 222 1.1 riastrad * encountered in bytes, or a negative value if no difference was found. 223 1.1 riastrad */ 224 1.1 riastrad static ssize_t vmw_find_last_diff(const u8 *dst, const u8 *src, size_t size, 225 1.1 riastrad size_t granularity) 226 1.1 riastrad { 227 1.1 riastrad dst += size; 228 1.1 riastrad src += size; 229 1.1 riastrad 230 1.1 riastrad #ifdef CONFIG_64BIT 231 1.1 riastrad VMW_TRY_FIND_LAST_DIFF(u64); 232 1.1 riastrad #endif 233 1.1 riastrad VMW_TRY_FIND_LAST_DIFF(u32); 234 1.1 riastrad VMW_TRY_FIND_LAST_DIFF(u16); 235 1.1 riastrad 236 1.1 riastrad return round_down(vmw_find_last_diff_u8(dst, src, size) - 1, 237 1.1 riastrad granularity); 238 1.1 riastrad } 239 1.1 riastrad 240 1.1 riastrad 241 1.1 riastrad /** 242 1.1 riastrad * vmw_memcpy - A wrapper around kernel memcpy with allowing to plug it into a 243 1.1 riastrad * struct vmw_diff_cpy. 244 1.1 riastrad * 245 1.1 riastrad * @diff: The struct vmw_diff_cpy closure argument (unused). 246 1.1 riastrad * @dest: The copy destination. 247 1.1 riastrad * @src: The copy source. 248 1.1 riastrad * @n: Number of bytes to copy. 249 1.1 riastrad */ 250 1.1 riastrad void vmw_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, size_t n) 251 1.1 riastrad { 252 1.1 riastrad memcpy(dest, src, n); 253 1.1 riastrad } 254 1.1 riastrad 255 1.1 riastrad 256 1.1 riastrad /** 257 1.1 riastrad * vmw_adjust_rect - Adjust rectangle coordinates for newly found difference 258 1.1 riastrad * 259 1.1 riastrad * @diff: The struct vmw_diff_cpy used to track the modified bounding box. 260 1.1 riastrad * @diff_offs: The offset from @diff->line_offset where the difference was 261 1.1 riastrad * found. 262 1.1 riastrad */ 263 1.1 riastrad static void vmw_adjust_rect(struct vmw_diff_cpy *diff, size_t diff_offs) 264 1.1 riastrad { 265 1.1 riastrad size_t offs = (diff_offs + diff->line_offset) / diff->cpp; 266 1.1 riastrad struct drm_rect *rect = &diff->rect; 267 1.1 riastrad 268 1.1 riastrad rect->x1 = min_t(int, rect->x1, offs); 269 1.1 riastrad rect->x2 = max_t(int, rect->x2, offs + 1); 270 1.1 riastrad rect->y1 = min_t(int, rect->y1, diff->line); 271 1.1 riastrad rect->y2 = max_t(int, rect->y2, diff->line + 1); 272 1.1 riastrad } 273 1.1 riastrad 274 1.1 riastrad /** 275 1.1 riastrad * vmw_diff_memcpy - memcpy that creates a bounding box of modified content. 276 1.1 riastrad * 277 1.1 riastrad * @diff: The struct vmw_diff_cpy used to track the modified bounding box. 278 1.1 riastrad * @dest: The copy destination. 279 1.1 riastrad * @src: The copy source. 280 1.1 riastrad * @n: Number of bytes to copy. 281 1.1 riastrad * 282 1.1 riastrad * In order to correctly track the modified content, the field @diff->line must 283 1.1 riastrad * be pre-loaded with the current line number, the field @diff->line_offset must 284 1.1 riastrad * be pre-loaded with the line offset in bytes where the copy starts, and 285 1.1 riastrad * finally the field @diff->cpp need to be preloaded with the number of bytes 286 1.1 riastrad * per unit in the horizontal direction of the area we're examining. 287 1.1 riastrad * Typically bytes per pixel. 288 1.1 riastrad * This is needed to know the needed granularity of the difference computing 289 1.1 riastrad * operations. A higher cpp generally leads to faster execution at the cost of 290 1.1 riastrad * bounding box width precision. 291 1.1 riastrad */ 292 1.1 riastrad void vmw_diff_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, 293 1.1 riastrad size_t n) 294 1.1 riastrad { 295 1.1 riastrad ssize_t csize, byte_len; 296 1.1 riastrad 297 1.1 riastrad if (WARN_ON_ONCE(round_down(n, diff->cpp) != n)) 298 1.1 riastrad return; 299 1.1 riastrad 300 1.1 riastrad /* TODO: Possibly use a single vmw_find_first_diff per line? */ 301 1.1 riastrad csize = vmw_find_first_diff(dest, src, n, diff->cpp); 302 1.1 riastrad if (csize < n) { 303 1.1 riastrad vmw_adjust_rect(diff, csize); 304 1.1 riastrad byte_len = diff->cpp; 305 1.1 riastrad 306 1.1 riastrad /* 307 1.1 riastrad * Starting from where first difference was found, find 308 1.1 riastrad * location of last difference, and then copy. 309 1.1 riastrad */ 310 1.1 riastrad diff->line_offset += csize; 311 1.1 riastrad dest += csize; 312 1.1 riastrad src += csize; 313 1.1 riastrad n -= csize; 314 1.1 riastrad csize = vmw_find_last_diff(dest, src, n, diff->cpp); 315 1.1 riastrad if (csize >= 0) { 316 1.1 riastrad byte_len += csize; 317 1.1 riastrad vmw_adjust_rect(diff, csize); 318 1.1 riastrad } 319 1.1 riastrad memcpy(dest, src, byte_len); 320 1.1 riastrad } 321 1.1 riastrad diff->line_offset += n; 322 1.1 riastrad } 323 1.1 riastrad 324 1.1 riastrad /** 325 1.1 riastrad * struct vmw_bo_blit_line_data - Convenience argument to vmw_bo_cpu_blit_line 326 1.1 riastrad * 327 1.1 riastrad * @mapped_dst: Already mapped destination page index in @dst_pages. 328 1.1 riastrad * @dst_addr: Kernel virtual address of mapped destination page. 329 1.1 riastrad * @dst_pages: Array of destination bo pages. 330 1.1 riastrad * @dst_num_pages: Number of destination bo pages. 331 1.1 riastrad * @dst_prot: Destination bo page protection. 332 1.1 riastrad * @mapped_src: Already mapped source page index in @dst_pages. 333 1.1 riastrad * @src_addr: Kernel virtual address of mapped source page. 334 1.1 riastrad * @src_pages: Array of source bo pages. 335 1.1 riastrad * @src_num_pages: Number of source bo pages. 336 1.1 riastrad * @src_prot: Source bo page protection. 337 1.1 riastrad * @diff: Struct vmw_diff_cpy, in the end forwarded to the memcpy routine. 338 1.1 riastrad */ 339 1.1 riastrad struct vmw_bo_blit_line_data { 340 1.1 riastrad u32 mapped_dst; 341 1.1 riastrad u8 *dst_addr; 342 1.1 riastrad struct page **dst_pages; 343 1.1 riastrad u32 dst_num_pages; 344 1.1 riastrad pgprot_t dst_prot; 345 1.1 riastrad u32 mapped_src; 346 1.1 riastrad u8 *src_addr; 347 1.1 riastrad struct page **src_pages; 348 1.1 riastrad u32 src_num_pages; 349 1.1 riastrad pgprot_t src_prot; 350 1.1 riastrad struct vmw_diff_cpy *diff; 351 1.1 riastrad }; 352 1.1 riastrad 353 1.1 riastrad /** 354 1.1 riastrad * vmw_bo_cpu_blit_line - Blit part of a line from one bo to another. 355 1.1 riastrad * 356 1.1 riastrad * @d: Blit data as described above. 357 1.1 riastrad * @dst_offset: Destination copy start offset from start of bo. 358 1.1 riastrad * @src_offset: Source copy start offset from start of bo. 359 1.1 riastrad * @bytes_to_copy: Number of bytes to copy in this line. 360 1.1 riastrad */ 361 1.1 riastrad static int vmw_bo_cpu_blit_line(struct vmw_bo_blit_line_data *d, 362 1.1 riastrad u32 dst_offset, 363 1.1 riastrad u32 src_offset, 364 1.1 riastrad u32 bytes_to_copy) 365 1.1 riastrad { 366 1.1 riastrad struct vmw_diff_cpy *diff = d->diff; 367 1.1 riastrad 368 1.1 riastrad while (bytes_to_copy) { 369 1.1 riastrad u32 copy_size = bytes_to_copy; 370 1.1 riastrad u32 dst_page = dst_offset >> PAGE_SHIFT; 371 1.1 riastrad u32 src_page = src_offset >> PAGE_SHIFT; 372 1.1 riastrad u32 dst_page_offset = dst_offset & ~PAGE_MASK; 373 1.1 riastrad u32 src_page_offset = src_offset & ~PAGE_MASK; 374 1.1 riastrad bool unmap_dst = d->dst_addr && dst_page != d->mapped_dst; 375 1.1 riastrad bool unmap_src = d->src_addr && (src_page != d->mapped_src || 376 1.1 riastrad unmap_dst); 377 1.1 riastrad 378 1.1 riastrad copy_size = min_t(u32, copy_size, PAGE_SIZE - dst_page_offset); 379 1.1 riastrad copy_size = min_t(u32, copy_size, PAGE_SIZE - src_page_offset); 380 1.1 riastrad 381 1.1 riastrad if (unmap_src) { 382 1.1 riastrad ttm_kunmap_atomic_prot(d->src_addr, d->src_prot); 383 1.1 riastrad d->src_addr = NULL; 384 1.1 riastrad } 385 1.1 riastrad 386 1.1 riastrad if (unmap_dst) { 387 1.1 riastrad ttm_kunmap_atomic_prot(d->dst_addr, d->dst_prot); 388 1.1 riastrad d->dst_addr = NULL; 389 1.1 riastrad } 390 1.1 riastrad 391 1.1 riastrad if (!d->dst_addr) { 392 1.1 riastrad if (WARN_ON_ONCE(dst_page >= d->dst_num_pages)) 393 1.1 riastrad return -EINVAL; 394 1.1 riastrad 395 1.1 riastrad d->dst_addr = 396 1.1 riastrad ttm_kmap_atomic_prot(d->dst_pages[dst_page], 397 1.1 riastrad d->dst_prot); 398 1.1 riastrad if (!d->dst_addr) 399 1.1 riastrad return -ENOMEM; 400 1.1 riastrad 401 1.1 riastrad d->mapped_dst = dst_page; 402 1.1 riastrad } 403 1.1 riastrad 404 1.1 riastrad if (!d->src_addr) { 405 1.1 riastrad if (WARN_ON_ONCE(src_page >= d->src_num_pages)) 406 1.1 riastrad return -EINVAL; 407 1.1 riastrad 408 1.1 riastrad d->src_addr = 409 1.1 riastrad ttm_kmap_atomic_prot(d->src_pages[src_page], 410 1.1 riastrad d->src_prot); 411 1.1 riastrad if (!d->src_addr) 412 1.1 riastrad return -ENOMEM; 413 1.1 riastrad 414 1.1 riastrad d->mapped_src = src_page; 415 1.1 riastrad } 416 1.1 riastrad diff->do_cpy(diff, d->dst_addr + dst_page_offset, 417 1.1 riastrad d->src_addr + src_page_offset, copy_size); 418 1.1 riastrad 419 1.1 riastrad bytes_to_copy -= copy_size; 420 1.1 riastrad dst_offset += copy_size; 421 1.1 riastrad src_offset += copy_size; 422 1.1 riastrad } 423 1.1 riastrad 424 1.1 riastrad return 0; 425 1.1 riastrad } 426 1.1 riastrad 427 1.1 riastrad /** 428 1.1 riastrad * ttm_bo_cpu_blit - in-kernel cpu blit. 429 1.1 riastrad * 430 1.1 riastrad * @dst: Destination buffer object. 431 1.1 riastrad * @dst_offset: Destination offset of blit start in bytes. 432 1.1 riastrad * @dst_stride: Destination stride in bytes. 433 1.1 riastrad * @src: Source buffer object. 434 1.1 riastrad * @src_offset: Source offset of blit start in bytes. 435 1.1 riastrad * @src_stride: Source stride in bytes. 436 1.1 riastrad * @w: Width of blit. 437 1.1 riastrad * @h: Height of blit. 438 1.1 riastrad * return: Zero on success. Negative error value on failure. Will print out 439 1.1 riastrad * kernel warnings on caller bugs. 440 1.1 riastrad * 441 1.1 riastrad * Performs a CPU blit from one buffer object to another avoiding a full 442 1.1 riastrad * bo vmap which may exhaust- or fragment vmalloc space. 443 1.1 riastrad * On supported architectures (x86), we're using kmap_atomic which avoids 444 1.1 riastrad * cross-processor TLB- and cache flushes and may, on non-HIGHMEM systems 445 1.1 riastrad * reference already set-up mappings. 446 1.1 riastrad * 447 1.1 riastrad * Neither of the buffer objects may be placed in PCI memory 448 1.1 riastrad * (Fixed memory in TTM terminology) when using this function. 449 1.1 riastrad */ 450 1.1 riastrad int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, 451 1.1 riastrad u32 dst_offset, u32 dst_stride, 452 1.1 riastrad struct ttm_buffer_object *src, 453 1.1 riastrad u32 src_offset, u32 src_stride, 454 1.1 riastrad u32 w, u32 h, 455 1.1 riastrad struct vmw_diff_cpy *diff) 456 1.1 riastrad { 457 1.1 riastrad struct ttm_operation_ctx ctx = { 458 1.1 riastrad .interruptible = false, 459 1.1 riastrad .no_wait_gpu = false 460 1.1 riastrad }; 461 1.1 riastrad u32 j, initial_line = dst_offset / dst_stride; 462 1.1 riastrad struct vmw_bo_blit_line_data d; 463 1.1 riastrad int ret = 0; 464 1.1 riastrad 465 1.1 riastrad /* Buffer objects need to be either pinned or reserved: */ 466 1.1 riastrad if (!(dst->mem.placement & TTM_PL_FLAG_NO_EVICT)) 467 1.1 riastrad dma_resv_assert_held(dst->base.resv); 468 1.1 riastrad if (!(src->mem.placement & TTM_PL_FLAG_NO_EVICT)) 469 1.1 riastrad dma_resv_assert_held(src->base.resv); 470 1.1 riastrad 471 1.1 riastrad if (dst->ttm->state == tt_unpopulated) { 472 1.1 riastrad ret = dst->ttm->bdev->driver->ttm_tt_populate(dst->ttm, &ctx); 473 1.1 riastrad if (ret) 474 1.1 riastrad return ret; 475 1.1 riastrad } 476 1.1 riastrad 477 1.1 riastrad if (src->ttm->state == tt_unpopulated) { 478 1.1 riastrad ret = src->ttm->bdev->driver->ttm_tt_populate(src->ttm, &ctx); 479 1.1 riastrad if (ret) 480 1.1 riastrad return ret; 481 1.1 riastrad } 482 1.1 riastrad 483 1.1 riastrad d.mapped_dst = 0; 484 1.1 riastrad d.mapped_src = 0; 485 1.1 riastrad d.dst_addr = NULL; 486 1.1 riastrad d.src_addr = NULL; 487 1.1 riastrad d.dst_pages = dst->ttm->pages; 488 1.1 riastrad d.src_pages = src->ttm->pages; 489 1.1 riastrad d.dst_num_pages = dst->num_pages; 490 1.1 riastrad d.src_num_pages = src->num_pages; 491 1.1 riastrad d.dst_prot = ttm_io_prot(dst->mem.placement, PAGE_KERNEL); 492 1.1 riastrad d.src_prot = ttm_io_prot(src->mem.placement, PAGE_KERNEL); 493 1.1 riastrad d.diff = diff; 494 1.1 riastrad 495 1.1 riastrad for (j = 0; j < h; ++j) { 496 1.1 riastrad diff->line = j + initial_line; 497 1.1 riastrad diff->line_offset = dst_offset % dst_stride; 498 1.1 riastrad ret = vmw_bo_cpu_blit_line(&d, dst_offset, src_offset, w); 499 1.1 riastrad if (ret) 500 1.1 riastrad goto out; 501 1.1 riastrad 502 1.1 riastrad dst_offset += dst_stride; 503 1.1 riastrad src_offset += src_stride; 504 1.1 riastrad } 505 1.1 riastrad out: 506 1.1 riastrad if (d.src_addr) 507 1.1 riastrad ttm_kunmap_atomic_prot(d.src_addr, d.src_prot); 508 1.1 riastrad if (d.dst_addr) 509 1.1 riastrad ttm_kunmap_atomic_prot(d.dst_addr, d.dst_prot); 510 1.1 riastrad 511 1.1 riastrad return ret; 512 1.1 riastrad } 513