18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
28c2ecf20Sopenharmony_ci/**************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
128c2ecf20Sopenharmony_ci * the following conditions:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
168c2ecf20Sopenharmony_ci * of the Software.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci **************************************************************************/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h"
298c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_bo_driver.h>
308c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
318c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_page_alloc.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct ttm_place vram_placement_flags = {
348c2ecf20Sopenharmony_ci	.fpfn = 0,
358c2ecf20Sopenharmony_ci	.lpfn = 0,
368c2ecf20Sopenharmony_ci	.mem_type = TTM_PL_VRAM,
378c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct ttm_place vram_ne_placement_flags = {
418c2ecf20Sopenharmony_ci	.fpfn = 0,
428c2ecf20Sopenharmony_ci	.lpfn = 0,
438c2ecf20Sopenharmony_ci	.mem_type = TTM_PL_VRAM,
448c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic const struct ttm_place sys_placement_flags = {
488c2ecf20Sopenharmony_ci	.fpfn = 0,
498c2ecf20Sopenharmony_ci	.lpfn = 0,
508c2ecf20Sopenharmony_ci	.mem_type = TTM_PL_SYSTEM,
518c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic const struct ttm_place sys_ne_placement_flags = {
558c2ecf20Sopenharmony_ci	.fpfn = 0,
568c2ecf20Sopenharmony_ci	.lpfn = 0,
578c2ecf20Sopenharmony_ci	.mem_type = TTM_PL_SYSTEM,
588c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const struct ttm_place gmr_placement_flags = {
628c2ecf20Sopenharmony_ci	.fpfn = 0,
638c2ecf20Sopenharmony_ci	.lpfn = 0,
648c2ecf20Sopenharmony_ci	.mem_type = VMW_PL_GMR,
658c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic const struct ttm_place gmr_ne_placement_flags = {
698c2ecf20Sopenharmony_ci	.fpfn = 0,
708c2ecf20Sopenharmony_ci	.lpfn = 0,
718c2ecf20Sopenharmony_ci	.mem_type = VMW_PL_GMR,
728c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct ttm_place mob_placement_flags = {
768c2ecf20Sopenharmony_ci	.fpfn = 0,
778c2ecf20Sopenharmony_ci	.lpfn = 0,
788c2ecf20Sopenharmony_ci	.mem_type = VMW_PL_MOB,
798c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED
808c2ecf20Sopenharmony_ci};
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic const struct ttm_place mob_ne_placement_flags = {
838c2ecf20Sopenharmony_ci	.fpfn = 0,
848c2ecf20Sopenharmony_ci	.lpfn = 0,
858c2ecf20Sopenharmony_ci	.mem_type = VMW_PL_MOB,
868c2ecf20Sopenharmony_ci	.flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct ttm_placement vmw_vram_placement = {
908c2ecf20Sopenharmony_ci	.num_placement = 1,
918c2ecf20Sopenharmony_ci	.placement = &vram_placement_flags,
928c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
938c2ecf20Sopenharmony_ci	.busy_placement = &vram_placement_flags
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic const struct ttm_place vram_gmr_placement_flags[] = {
978c2ecf20Sopenharmony_ci	{
988c2ecf20Sopenharmony_ci		.fpfn = 0,
998c2ecf20Sopenharmony_ci		.lpfn = 0,
1008c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_VRAM,
1018c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1028c2ecf20Sopenharmony_ci	}, {
1038c2ecf20Sopenharmony_ci		.fpfn = 0,
1048c2ecf20Sopenharmony_ci		.lpfn = 0,
1058c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_GMR,
1068c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic const struct ttm_place gmr_vram_placement_flags[] = {
1118c2ecf20Sopenharmony_ci	{
1128c2ecf20Sopenharmony_ci		.fpfn = 0,
1138c2ecf20Sopenharmony_ci		.lpfn = 0,
1148c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_GMR,
1158c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1168c2ecf20Sopenharmony_ci	}, {
1178c2ecf20Sopenharmony_ci		.fpfn = 0,
1188c2ecf20Sopenharmony_ci		.lpfn = 0,
1198c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_VRAM,
1208c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct ttm_placement vmw_vram_gmr_placement = {
1258c2ecf20Sopenharmony_ci	.num_placement = 2,
1268c2ecf20Sopenharmony_ci	.placement = vram_gmr_placement_flags,
1278c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1288c2ecf20Sopenharmony_ci	.busy_placement = &gmr_placement_flags
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic const struct ttm_place vram_gmr_ne_placement_flags[] = {
1328c2ecf20Sopenharmony_ci	{
1338c2ecf20Sopenharmony_ci		.fpfn = 0,
1348c2ecf20Sopenharmony_ci		.lpfn = 0,
1358c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_VRAM,
1368c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED |
1378c2ecf20Sopenharmony_ci			 TTM_PL_FLAG_NO_EVICT
1388c2ecf20Sopenharmony_ci	}, {
1398c2ecf20Sopenharmony_ci		.fpfn = 0,
1408c2ecf20Sopenharmony_ci		.lpfn = 0,
1418c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_GMR,
1428c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED |
1438c2ecf20Sopenharmony_ci			 TTM_PL_FLAG_NO_EVICT
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistruct ttm_placement vmw_vram_gmr_ne_placement = {
1488c2ecf20Sopenharmony_ci	.num_placement = 2,
1498c2ecf20Sopenharmony_ci	.placement = vram_gmr_ne_placement_flags,
1508c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1518c2ecf20Sopenharmony_ci	.busy_placement = &gmr_ne_placement_flags
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistruct ttm_placement vmw_vram_sys_placement = {
1558c2ecf20Sopenharmony_ci	.num_placement = 1,
1568c2ecf20Sopenharmony_ci	.placement = &vram_placement_flags,
1578c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1588c2ecf20Sopenharmony_ci	.busy_placement = &sys_placement_flags
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistruct ttm_placement vmw_vram_ne_placement = {
1628c2ecf20Sopenharmony_ci	.num_placement = 1,
1638c2ecf20Sopenharmony_ci	.placement = &vram_ne_placement_flags,
1648c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1658c2ecf20Sopenharmony_ci	.busy_placement = &vram_ne_placement_flags
1668c2ecf20Sopenharmony_ci};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistruct ttm_placement vmw_sys_placement = {
1698c2ecf20Sopenharmony_ci	.num_placement = 1,
1708c2ecf20Sopenharmony_ci	.placement = &sys_placement_flags,
1718c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1728c2ecf20Sopenharmony_ci	.busy_placement = &sys_placement_flags
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistruct ttm_placement vmw_sys_ne_placement = {
1768c2ecf20Sopenharmony_ci	.num_placement = 1,
1778c2ecf20Sopenharmony_ci	.placement = &sys_ne_placement_flags,
1788c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
1798c2ecf20Sopenharmony_ci	.busy_placement = &sys_ne_placement_flags
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const struct ttm_place evictable_placement_flags[] = {
1838c2ecf20Sopenharmony_ci	{
1848c2ecf20Sopenharmony_ci		.fpfn = 0,
1858c2ecf20Sopenharmony_ci		.lpfn = 0,
1868c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_SYSTEM,
1878c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1888c2ecf20Sopenharmony_ci	}, {
1898c2ecf20Sopenharmony_ci		.fpfn = 0,
1908c2ecf20Sopenharmony_ci		.lpfn = 0,
1918c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_VRAM,
1928c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1938c2ecf20Sopenharmony_ci	}, {
1948c2ecf20Sopenharmony_ci		.fpfn = 0,
1958c2ecf20Sopenharmony_ci		.lpfn = 0,
1968c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_GMR,
1978c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
1988c2ecf20Sopenharmony_ci	}, {
1998c2ecf20Sopenharmony_ci		.fpfn = 0,
2008c2ecf20Sopenharmony_ci		.lpfn = 0,
2018c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_MOB,
2028c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic const struct ttm_place nonfixed_placement_flags[] = {
2078c2ecf20Sopenharmony_ci	{
2088c2ecf20Sopenharmony_ci		.fpfn = 0,
2098c2ecf20Sopenharmony_ci		.lpfn = 0,
2108c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_SYSTEM,
2118c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
2128c2ecf20Sopenharmony_ci	}, {
2138c2ecf20Sopenharmony_ci		.fpfn = 0,
2148c2ecf20Sopenharmony_ci		.lpfn = 0,
2158c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_GMR,
2168c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
2178c2ecf20Sopenharmony_ci	}, {
2188c2ecf20Sopenharmony_ci		.fpfn = 0,
2198c2ecf20Sopenharmony_ci		.lpfn = 0,
2208c2ecf20Sopenharmony_ci		.mem_type = VMW_PL_MOB,
2218c2ecf20Sopenharmony_ci		.flags = TTM_PL_FLAG_CACHED
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci};
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistruct ttm_placement vmw_evictable_placement = {
2268c2ecf20Sopenharmony_ci	.num_placement = 4,
2278c2ecf20Sopenharmony_ci	.placement = evictable_placement_flags,
2288c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
2298c2ecf20Sopenharmony_ci	.busy_placement = &sys_placement_flags
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistruct ttm_placement vmw_srf_placement = {
2338c2ecf20Sopenharmony_ci	.num_placement = 1,
2348c2ecf20Sopenharmony_ci	.num_busy_placement = 2,
2358c2ecf20Sopenharmony_ci	.placement = &gmr_placement_flags,
2368c2ecf20Sopenharmony_ci	.busy_placement = gmr_vram_placement_flags
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistruct ttm_placement vmw_mob_placement = {
2408c2ecf20Sopenharmony_ci	.num_placement = 1,
2418c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
2428c2ecf20Sopenharmony_ci	.placement = &mob_placement_flags,
2438c2ecf20Sopenharmony_ci	.busy_placement = &mob_placement_flags
2448c2ecf20Sopenharmony_ci};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistruct ttm_placement vmw_mob_ne_placement = {
2478c2ecf20Sopenharmony_ci	.num_placement = 1,
2488c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
2498c2ecf20Sopenharmony_ci	.placement = &mob_ne_placement_flags,
2508c2ecf20Sopenharmony_ci	.busy_placement = &mob_ne_placement_flags
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistruct ttm_placement vmw_nonfixed_placement = {
2548c2ecf20Sopenharmony_ci	.num_placement = 3,
2558c2ecf20Sopenharmony_ci	.placement = nonfixed_placement_flags,
2568c2ecf20Sopenharmony_ci	.num_busy_placement = 1,
2578c2ecf20Sopenharmony_ci	.busy_placement = &sys_placement_flags
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistruct vmw_ttm_tt {
2618c2ecf20Sopenharmony_ci	struct ttm_dma_tt dma_ttm;
2628c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv;
2638c2ecf20Sopenharmony_ci	int gmr_id;
2648c2ecf20Sopenharmony_ci	struct vmw_mob *mob;
2658c2ecf20Sopenharmony_ci	int mem_type;
2668c2ecf20Sopenharmony_ci	struct sg_table sgt;
2678c2ecf20Sopenharmony_ci	struct vmw_sg_table vsgt;
2688c2ecf20Sopenharmony_ci	uint64_t sg_alloc_size;
2698c2ecf20Sopenharmony_ci	bool mapped;
2708c2ecf20Sopenharmony_ci	bool bound;
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciconst size_t vmw_tt_size = sizeof(struct vmw_ttm_tt);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/**
2768c2ecf20Sopenharmony_ci * Helper functions to advance a struct vmw_piter iterator.
2778c2ecf20Sopenharmony_ci *
2788c2ecf20Sopenharmony_ci * @viter: Pointer to the iterator.
2798c2ecf20Sopenharmony_ci *
2808c2ecf20Sopenharmony_ci * These functions return false if past the end of the list,
2818c2ecf20Sopenharmony_ci * true otherwise. Functions are selected depending on the current
2828c2ecf20Sopenharmony_ci * DMA mapping mode.
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistatic bool __vmw_piter_non_sg_next(struct vmw_piter *viter)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	return ++(viter->i) < viter->num_pages;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic bool __vmw_piter_sg_next(struct vmw_piter *viter)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	bool ret = __vmw_piter_non_sg_next(viter);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	return __sg_page_iter_dma_next(&viter->iter) && ret;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/**
2988c2ecf20Sopenharmony_ci * Helper functions to return a pointer to the current page.
2998c2ecf20Sopenharmony_ci *
3008c2ecf20Sopenharmony_ci * @viter: Pointer to the iterator
3018c2ecf20Sopenharmony_ci *
3028c2ecf20Sopenharmony_ci * These functions return a pointer to the page currently
3038c2ecf20Sopenharmony_ci * pointed to by @viter. Functions are selected depending on the
3048c2ecf20Sopenharmony_ci * current mapping mode.
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_cistatic struct page *__vmw_piter_non_sg_page(struct vmw_piter *viter)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	return viter->pages[viter->i];
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/**
3128c2ecf20Sopenharmony_ci * Helper functions to return the DMA address of the current page.
3138c2ecf20Sopenharmony_ci *
3148c2ecf20Sopenharmony_ci * @viter: Pointer to the iterator
3158c2ecf20Sopenharmony_ci *
3168c2ecf20Sopenharmony_ci * These functions return the DMA address of the page currently
3178c2ecf20Sopenharmony_ci * pointed to by @viter. Functions are selected depending on the
3188c2ecf20Sopenharmony_ci * current mapping mode.
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_cistatic dma_addr_t __vmw_piter_phys_addr(struct vmw_piter *viter)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	return page_to_phys(viter->pages[viter->i]);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	return viter->addrs[viter->i];
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	return sg_page_iter_dma_address(&viter->iter);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci/**
3378c2ecf20Sopenharmony_ci * vmw_piter_start - Initialize a struct vmw_piter.
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * @viter: Pointer to the iterator to initialize
3408c2ecf20Sopenharmony_ci * @vsgt: Pointer to a struct vmw_sg_table to initialize from
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * Note that we're following the convention of __sg_page_iter_start, so that
3438c2ecf20Sopenharmony_ci * the iterator doesn't point to a valid page after initialization; it has
3448c2ecf20Sopenharmony_ci * to be advanced one step first.
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_civoid vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
3478c2ecf20Sopenharmony_ci		     unsigned long p_offset)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	viter->i = p_offset - 1;
3508c2ecf20Sopenharmony_ci	viter->num_pages = vsgt->num_pages;
3518c2ecf20Sopenharmony_ci	viter->page = &__vmw_piter_non_sg_page;
3528c2ecf20Sopenharmony_ci	viter->pages = vsgt->pages;
3538c2ecf20Sopenharmony_ci	switch (vsgt->mode) {
3548c2ecf20Sopenharmony_ci	case vmw_dma_phys:
3558c2ecf20Sopenharmony_ci		viter->next = &__vmw_piter_non_sg_next;
3568c2ecf20Sopenharmony_ci		viter->dma_address = &__vmw_piter_phys_addr;
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	case vmw_dma_alloc_coherent:
3598c2ecf20Sopenharmony_ci		viter->next = &__vmw_piter_non_sg_next;
3608c2ecf20Sopenharmony_ci		viter->dma_address = &__vmw_piter_dma_addr;
3618c2ecf20Sopenharmony_ci		viter->addrs = vsgt->addrs;
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci	case vmw_dma_map_populate:
3648c2ecf20Sopenharmony_ci	case vmw_dma_map_bind:
3658c2ecf20Sopenharmony_ci		viter->next = &__vmw_piter_sg_next;
3668c2ecf20Sopenharmony_ci		viter->dma_address = &__vmw_piter_sg_addr;
3678c2ecf20Sopenharmony_ci		__sg_page_iter_start(&viter->iter.base, vsgt->sgt->sgl,
3688c2ecf20Sopenharmony_ci				     vsgt->sgt->orig_nents, p_offset);
3698c2ecf20Sopenharmony_ci		break;
3708c2ecf20Sopenharmony_ci	default:
3718c2ecf20Sopenharmony_ci		BUG();
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/**
3768c2ecf20Sopenharmony_ci * vmw_ttm_unmap_from_dma - unmap  device addresses previsouly mapped for
3778c2ecf20Sopenharmony_ci * TTM pages
3788c2ecf20Sopenharmony_ci *
3798c2ecf20Sopenharmony_ci * @vmw_tt: Pointer to a struct vmw_ttm_backend
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * Used to free dma mappings previously mapped by vmw_ttm_map_for_dma.
3828c2ecf20Sopenharmony_ci */
3838c2ecf20Sopenharmony_cistatic void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt *vmw_tt)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct device *dev = vmw_tt->dev_priv->dev->dev;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	dma_unmap_sgtable(dev, &vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
3888c2ecf20Sopenharmony_ci	vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci/**
3928c2ecf20Sopenharmony_ci * vmw_ttm_map_for_dma - map TTM pages to get device addresses
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * @vmw_tt: Pointer to a struct vmw_ttm_backend
3958c2ecf20Sopenharmony_ci *
3968c2ecf20Sopenharmony_ci * This function is used to get device addresses from the kernel DMA layer.
3978c2ecf20Sopenharmony_ci * However, it's violating the DMA API in that when this operation has been
3988c2ecf20Sopenharmony_ci * performed, it's illegal for the CPU to write to the pages without first
3998c2ecf20Sopenharmony_ci * unmapping the DMA mappings, or calling dma_sync_sg_for_cpu(). It is
4008c2ecf20Sopenharmony_ci * therefore only legal to call this function if we know that the function
4018c2ecf20Sopenharmony_ci * dma_sync_sg_for_cpu() is a NOP, and dma_sync_sg_for_device() is at most
4028c2ecf20Sopenharmony_ci * a CPU write buffer flush.
4038c2ecf20Sopenharmony_ci */
4048c2ecf20Sopenharmony_cistatic int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct device *dev = vmw_tt->dev_priv->dev->dev;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return dma_map_sgtable(dev, &vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/**
4128c2ecf20Sopenharmony_ci * vmw_ttm_map_dma - Make sure TTM pages are visible to the device
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * @vmw_tt: Pointer to a struct vmw_ttm_tt
4158c2ecf20Sopenharmony_ci *
4168c2ecf20Sopenharmony_ci * Select the correct function for and make sure the TTM pages are
4178c2ecf20Sopenharmony_ci * visible to the device. Allocate storage for the device mappings.
4188c2ecf20Sopenharmony_ci * If a mapping has already been performed, indicated by the storage
4198c2ecf20Sopenharmony_ci * pointer being non NULL, the function returns success.
4208c2ecf20Sopenharmony_ci */
4218c2ecf20Sopenharmony_cistatic int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_tt->dev_priv;
4248c2ecf20Sopenharmony_ci	struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
4258c2ecf20Sopenharmony_ci	struct vmw_sg_table *vsgt = &vmw_tt->vsgt;
4268c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
4278c2ecf20Sopenharmony_ci		.interruptible = true,
4288c2ecf20Sopenharmony_ci		.no_wait_gpu = false
4298c2ecf20Sopenharmony_ci	};
4308c2ecf20Sopenharmony_ci	struct vmw_piter iter;
4318c2ecf20Sopenharmony_ci	dma_addr_t old;
4328c2ecf20Sopenharmony_ci	int ret = 0;
4338c2ecf20Sopenharmony_ci	static size_t sgl_size;
4348c2ecf20Sopenharmony_ci	static size_t sgt_size;
4358c2ecf20Sopenharmony_ci	struct scatterlist *sg;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (vmw_tt->mapped)
4388c2ecf20Sopenharmony_ci		return 0;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	vsgt->mode = dev_priv->map_mode;
4418c2ecf20Sopenharmony_ci	vsgt->pages = vmw_tt->dma_ttm.ttm.pages;
4428c2ecf20Sopenharmony_ci	vsgt->num_pages = vmw_tt->dma_ttm.ttm.num_pages;
4438c2ecf20Sopenharmony_ci	vsgt->addrs = vmw_tt->dma_ttm.dma_address;
4448c2ecf20Sopenharmony_ci	vsgt->sgt = &vmw_tt->sgt;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	switch (dev_priv->map_mode) {
4478c2ecf20Sopenharmony_ci	case vmw_dma_map_bind:
4488c2ecf20Sopenharmony_ci	case vmw_dma_map_populate:
4498c2ecf20Sopenharmony_ci		if (unlikely(!sgl_size)) {
4508c2ecf20Sopenharmony_ci			sgl_size = ttm_round_pot(sizeof(struct scatterlist));
4518c2ecf20Sopenharmony_ci			sgt_size = ttm_round_pot(sizeof(struct sg_table));
4528c2ecf20Sopenharmony_ci		}
4538c2ecf20Sopenharmony_ci		vmw_tt->sg_alloc_size = sgt_size + sgl_size * vsgt->num_pages;
4548c2ecf20Sopenharmony_ci		ret = ttm_mem_global_alloc(glob, vmw_tt->sg_alloc_size, &ctx);
4558c2ecf20Sopenharmony_ci		if (unlikely(ret != 0))
4568c2ecf20Sopenharmony_ci			return ret;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		sg = __sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages,
4598c2ecf20Sopenharmony_ci				vsgt->num_pages, 0,
4608c2ecf20Sopenharmony_ci				(unsigned long) vsgt->num_pages << PAGE_SHIFT,
4618c2ecf20Sopenharmony_ci				dma_get_max_seg_size(dev_priv->dev->dev),
4628c2ecf20Sopenharmony_ci				NULL, 0, GFP_KERNEL);
4638c2ecf20Sopenharmony_ci		if (IS_ERR(sg)) {
4648c2ecf20Sopenharmony_ci			ret = PTR_ERR(sg);
4658c2ecf20Sopenharmony_ci			goto out_sg_alloc_fail;
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (vsgt->num_pages > vmw_tt->sgt.orig_nents) {
4698c2ecf20Sopenharmony_ci			uint64_t over_alloc =
4708c2ecf20Sopenharmony_ci				sgl_size * (vsgt->num_pages -
4718c2ecf20Sopenharmony_ci					    vmw_tt->sgt.orig_nents);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci			ttm_mem_global_free(glob, over_alloc);
4748c2ecf20Sopenharmony_ci			vmw_tt->sg_alloc_size -= over_alloc;
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		ret = vmw_ttm_map_for_dma(vmw_tt);
4788c2ecf20Sopenharmony_ci		if (unlikely(ret != 0))
4798c2ecf20Sopenharmony_ci			goto out_map_fail;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		break;
4828c2ecf20Sopenharmony_ci	default:
4838c2ecf20Sopenharmony_ci		break;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	old = ~((dma_addr_t) 0);
4878c2ecf20Sopenharmony_ci	vmw_tt->vsgt.num_regions = 0;
4888c2ecf20Sopenharmony_ci	for (vmw_piter_start(&iter, vsgt, 0); vmw_piter_next(&iter);) {
4898c2ecf20Sopenharmony_ci		dma_addr_t cur = vmw_piter_dma_addr(&iter);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		if (cur != old + PAGE_SIZE)
4928c2ecf20Sopenharmony_ci			vmw_tt->vsgt.num_regions++;
4938c2ecf20Sopenharmony_ci		old = cur;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	vmw_tt->mapped = true;
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ciout_map_fail:
5008c2ecf20Sopenharmony_ci	sg_free_table(vmw_tt->vsgt.sgt);
5018c2ecf20Sopenharmony_ci	vmw_tt->vsgt.sgt = NULL;
5028c2ecf20Sopenharmony_ciout_sg_alloc_fail:
5038c2ecf20Sopenharmony_ci	ttm_mem_global_free(glob, vmw_tt->sg_alloc_size);
5048c2ecf20Sopenharmony_ci	return ret;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/**
5088c2ecf20Sopenharmony_ci * vmw_ttm_unmap_dma - Tear down any TTM page device mappings
5098c2ecf20Sopenharmony_ci *
5108c2ecf20Sopenharmony_ci * @vmw_tt: Pointer to a struct vmw_ttm_tt
5118c2ecf20Sopenharmony_ci *
5128c2ecf20Sopenharmony_ci * Tear down any previously set up device DMA mappings and free
5138c2ecf20Sopenharmony_ci * any storage space allocated for them. If there are no mappings set up,
5148c2ecf20Sopenharmony_ci * this function is a NOP.
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistatic void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_tt->dev_priv;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (!vmw_tt->vsgt.sgt)
5218c2ecf20Sopenharmony_ci		return;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	switch (dev_priv->map_mode) {
5248c2ecf20Sopenharmony_ci	case vmw_dma_map_bind:
5258c2ecf20Sopenharmony_ci	case vmw_dma_map_populate:
5268c2ecf20Sopenharmony_ci		vmw_ttm_unmap_from_dma(vmw_tt);
5278c2ecf20Sopenharmony_ci		sg_free_table(vmw_tt->vsgt.sgt);
5288c2ecf20Sopenharmony_ci		vmw_tt->vsgt.sgt = NULL;
5298c2ecf20Sopenharmony_ci		ttm_mem_global_free(vmw_mem_glob(dev_priv),
5308c2ecf20Sopenharmony_ci				    vmw_tt->sg_alloc_size);
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	default:
5338c2ecf20Sopenharmony_ci		break;
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci	vmw_tt->mapped = false;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/**
5398c2ecf20Sopenharmony_ci * vmw_bo_sg_table - Return a struct vmw_sg_table object for a
5408c2ecf20Sopenharmony_ci * TTM buffer object
5418c2ecf20Sopenharmony_ci *
5428c2ecf20Sopenharmony_ci * @bo: Pointer to a struct ttm_buffer_object
5438c2ecf20Sopenharmony_ci *
5448c2ecf20Sopenharmony_ci * Returns a pointer to a struct vmw_sg_table object. The object should
5458c2ecf20Sopenharmony_ci * not be freed after use.
5468c2ecf20Sopenharmony_ci * Note that for the device addresses to be valid, the buffer object must
5478c2ecf20Sopenharmony_ci * either be reserved or pinned.
5488c2ecf20Sopenharmony_ci */
5498c2ecf20Sopenharmony_ciconst struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_tt =
5528c2ecf20Sopenharmony_ci		container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return &vmw_tt->vsgt;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic int vmw_ttm_bind(struct ttm_bo_device *bdev,
5598c2ecf20Sopenharmony_ci			struct ttm_tt *ttm, struct ttm_resource *bo_mem)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_be =
5628c2ecf20Sopenharmony_ci		container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
5638c2ecf20Sopenharmony_ci	int ret = 0;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (!bo_mem)
5668c2ecf20Sopenharmony_ci		return -EINVAL;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (vmw_be->bound)
5698c2ecf20Sopenharmony_ci		return 0;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	ret = vmw_ttm_map_dma(vmw_be);
5728c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
5738c2ecf20Sopenharmony_ci		return ret;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	vmw_be->gmr_id = bo_mem->start;
5768c2ecf20Sopenharmony_ci	vmw_be->mem_type = bo_mem->mem_type;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	switch (bo_mem->mem_type) {
5798c2ecf20Sopenharmony_ci	case VMW_PL_GMR:
5808c2ecf20Sopenharmony_ci		ret = vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
5818c2ecf20Sopenharmony_ci				    ttm->num_pages, vmw_be->gmr_id);
5828c2ecf20Sopenharmony_ci		break;
5838c2ecf20Sopenharmony_ci	case VMW_PL_MOB:
5848c2ecf20Sopenharmony_ci		if (unlikely(vmw_be->mob == NULL)) {
5858c2ecf20Sopenharmony_ci			vmw_be->mob =
5868c2ecf20Sopenharmony_ci				vmw_mob_create(ttm->num_pages);
5878c2ecf20Sopenharmony_ci			if (unlikely(vmw_be->mob == NULL))
5888c2ecf20Sopenharmony_ci				return -ENOMEM;
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		ret = vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob,
5928c2ecf20Sopenharmony_ci				    &vmw_be->vsgt, ttm->num_pages,
5938c2ecf20Sopenharmony_ci				    vmw_be->gmr_id);
5948c2ecf20Sopenharmony_ci		break;
5958c2ecf20Sopenharmony_ci	default:
5968c2ecf20Sopenharmony_ci		BUG();
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci	vmw_be->bound = true;
5998c2ecf20Sopenharmony_ci	return ret;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic void vmw_ttm_unbind(struct ttm_bo_device *bdev,
6038c2ecf20Sopenharmony_ci			   struct ttm_tt *ttm)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_be =
6068c2ecf20Sopenharmony_ci		container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (!vmw_be->bound)
6098c2ecf20Sopenharmony_ci		return;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	switch (vmw_be->mem_type) {
6128c2ecf20Sopenharmony_ci	case VMW_PL_GMR:
6138c2ecf20Sopenharmony_ci		vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
6148c2ecf20Sopenharmony_ci		break;
6158c2ecf20Sopenharmony_ci	case VMW_PL_MOB:
6168c2ecf20Sopenharmony_ci		vmw_mob_unbind(vmw_be->dev_priv, vmw_be->mob);
6178c2ecf20Sopenharmony_ci		break;
6188c2ecf20Sopenharmony_ci	default:
6198c2ecf20Sopenharmony_ci		BUG();
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
6238c2ecf20Sopenharmony_ci		vmw_ttm_unmap_dma(vmw_be);
6248c2ecf20Sopenharmony_ci	vmw_be->bound = false;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void vmw_ttm_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_be =
6318c2ecf20Sopenharmony_ci		container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	vmw_ttm_unbind(bdev, ttm);
6348c2ecf20Sopenharmony_ci	ttm_tt_destroy_common(bdev, ttm);
6358c2ecf20Sopenharmony_ci	vmw_ttm_unmap_dma(vmw_be);
6368c2ecf20Sopenharmony_ci	if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
6378c2ecf20Sopenharmony_ci		ttm_dma_tt_fini(&vmw_be->dma_ttm);
6388c2ecf20Sopenharmony_ci	else
6398c2ecf20Sopenharmony_ci		ttm_tt_fini(ttm);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (vmw_be->mob)
6428c2ecf20Sopenharmony_ci		vmw_mob_destroy(vmw_be->mob);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	kfree(vmw_be);
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic int vmw_ttm_populate(struct ttm_bo_device *bdev,
6498c2ecf20Sopenharmony_ci			    struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_tt =
6528c2ecf20Sopenharmony_ci		container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
6538c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_tt->dev_priv;
6548c2ecf20Sopenharmony_ci	struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
6558c2ecf20Sopenharmony_ci	int ret;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (ttm_tt_is_populated(ttm))
6588c2ecf20Sopenharmony_ci		return 0;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
6618c2ecf20Sopenharmony_ci		size_t size =
6628c2ecf20Sopenharmony_ci			ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
6638c2ecf20Sopenharmony_ci		ret = ttm_mem_global_alloc(glob, size, ctx);
6648c2ecf20Sopenharmony_ci		if (unlikely(ret != 0))
6658c2ecf20Sopenharmony_ci			return ret;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		ret = ttm_dma_populate(&vmw_tt->dma_ttm, dev_priv->dev->dev,
6688c2ecf20Sopenharmony_ci					ctx);
6698c2ecf20Sopenharmony_ci		if (unlikely(ret != 0))
6708c2ecf20Sopenharmony_ci			ttm_mem_global_free(glob, size);
6718c2ecf20Sopenharmony_ci	} else
6728c2ecf20Sopenharmony_ci		ret = ttm_pool_populate(ttm, ctx);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return ret;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic void vmw_ttm_unpopulate(struct ttm_bo_device *bdev,
6788c2ecf20Sopenharmony_ci			       struct ttm_tt *ttm)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
6818c2ecf20Sopenharmony_ci						 dma_ttm.ttm);
6828c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = vmw_tt->dev_priv;
6838c2ecf20Sopenharmony_ci	struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (vmw_tt->mob) {
6878c2ecf20Sopenharmony_ci		vmw_mob_destroy(vmw_tt->mob);
6888c2ecf20Sopenharmony_ci		vmw_tt->mob = NULL;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	vmw_ttm_unmap_dma(vmw_tt);
6928c2ecf20Sopenharmony_ci	if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
6938c2ecf20Sopenharmony_ci		size_t size =
6948c2ecf20Sopenharmony_ci			ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		ttm_dma_unpopulate(&vmw_tt->dma_ttm, dev_priv->dev->dev);
6978c2ecf20Sopenharmony_ci		ttm_mem_global_free(glob, size);
6988c2ecf20Sopenharmony_ci	} else
6998c2ecf20Sopenharmony_ci		ttm_pool_unpopulate(ttm);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
7038c2ecf20Sopenharmony_ci					uint32_t page_flags)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct vmw_ttm_tt *vmw_be;
7068c2ecf20Sopenharmony_ci	int ret;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
7098c2ecf20Sopenharmony_ci	if (!vmw_be)
7108c2ecf20Sopenharmony_ci		return NULL;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	vmw_be->dev_priv = container_of(bo->bdev, struct vmw_private, bdev);
7138c2ecf20Sopenharmony_ci	vmw_be->mob = NULL;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
7168c2ecf20Sopenharmony_ci		ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bo, page_flags);
7178c2ecf20Sopenharmony_ci	else
7188c2ecf20Sopenharmony_ci		ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bo, page_flags);
7198c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
7208c2ecf20Sopenharmony_ci		goto out_no_init;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return &vmw_be->dma_ttm.ttm;
7238c2ecf20Sopenharmony_ciout_no_init:
7248c2ecf20Sopenharmony_ci	kfree(vmw_be);
7258c2ecf20Sopenharmony_ci	return NULL;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic void vmw_evict_flags(struct ttm_buffer_object *bo,
7298c2ecf20Sopenharmony_ci		     struct ttm_placement *placement)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	*placement = vmw_sys_placement;
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct ttm_object_file *tfile =
7378c2ecf20Sopenharmony_ci		vmw_fpriv((struct drm_file *)filp->private_data)->tfile;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return vmw_user_bo_verify_access(bo, tfile);
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistatic int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	switch (mem->mem_type) {
7478c2ecf20Sopenharmony_ci	case TTM_PL_SYSTEM:
7488c2ecf20Sopenharmony_ci	case VMW_PL_GMR:
7498c2ecf20Sopenharmony_ci	case VMW_PL_MOB:
7508c2ecf20Sopenharmony_ci		return 0;
7518c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
7528c2ecf20Sopenharmony_ci		mem->bus.offset = (mem->start << PAGE_SHIFT) +
7538c2ecf20Sopenharmony_ci			dev_priv->vram_start;
7548c2ecf20Sopenharmony_ci		mem->bus.is_iomem = true;
7558c2ecf20Sopenharmony_ci		break;
7568c2ecf20Sopenharmony_ci	default:
7578c2ecf20Sopenharmony_ci		return -EINVAL;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci	return 0;
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci/**
7638c2ecf20Sopenharmony_ci * vmw_move_notify - TTM move_notify_callback
7648c2ecf20Sopenharmony_ci *
7658c2ecf20Sopenharmony_ci * @bo: The TTM buffer object about to move.
7668c2ecf20Sopenharmony_ci * @mem: The struct ttm_resource indicating to what memory
7678c2ecf20Sopenharmony_ci *       region the move is taking place.
7688c2ecf20Sopenharmony_ci *
7698c2ecf20Sopenharmony_ci * Calls move_notify for all subsystems needing it.
7708c2ecf20Sopenharmony_ci * (currently only resources).
7718c2ecf20Sopenharmony_ci */
7728c2ecf20Sopenharmony_cistatic void vmw_move_notify(struct ttm_buffer_object *bo,
7738c2ecf20Sopenharmony_ci			    bool evict,
7748c2ecf20Sopenharmony_ci			    struct ttm_resource *mem)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	vmw_bo_move_notify(bo, mem);
7778c2ecf20Sopenharmony_ci	vmw_query_move_notify(bo, mem);
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci/**
7828c2ecf20Sopenharmony_ci * vmw_swap_notify - TTM move_notify_callback
7838c2ecf20Sopenharmony_ci *
7848c2ecf20Sopenharmony_ci * @bo: The TTM buffer object about to be swapped out.
7858c2ecf20Sopenharmony_ci */
7868c2ecf20Sopenharmony_cistatic void vmw_swap_notify(struct ttm_buffer_object *bo)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	vmw_bo_swap_notify(bo);
7898c2ecf20Sopenharmony_ci	(void) ttm_bo_wait(bo, false, false);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistruct ttm_bo_driver vmw_bo_driver = {
7948c2ecf20Sopenharmony_ci	.ttm_tt_create = &vmw_ttm_tt_create,
7958c2ecf20Sopenharmony_ci	.ttm_tt_populate = &vmw_ttm_populate,
7968c2ecf20Sopenharmony_ci	.ttm_tt_unpopulate = &vmw_ttm_unpopulate,
7978c2ecf20Sopenharmony_ci	.ttm_tt_bind = &vmw_ttm_bind,
7988c2ecf20Sopenharmony_ci	.ttm_tt_unbind = &vmw_ttm_unbind,
7998c2ecf20Sopenharmony_ci	.ttm_tt_destroy = &vmw_ttm_destroy,
8008c2ecf20Sopenharmony_ci	.eviction_valuable = ttm_bo_eviction_valuable,
8018c2ecf20Sopenharmony_ci	.evict_flags = vmw_evict_flags,
8028c2ecf20Sopenharmony_ci	.move = NULL,
8038c2ecf20Sopenharmony_ci	.verify_access = vmw_verify_access,
8048c2ecf20Sopenharmony_ci	.move_notify = vmw_move_notify,
8058c2ecf20Sopenharmony_ci	.swap_notify = vmw_swap_notify,
8068c2ecf20Sopenharmony_ci	.io_mem_reserve = &vmw_ttm_io_mem_reserve,
8078c2ecf20Sopenharmony_ci};
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ciint vmw_bo_create_and_populate(struct vmw_private *dev_priv,
8108c2ecf20Sopenharmony_ci			       unsigned long bo_size,
8118c2ecf20Sopenharmony_ci			       struct ttm_buffer_object **bo_p)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = {
8148c2ecf20Sopenharmony_ci		.interruptible = false,
8158c2ecf20Sopenharmony_ci		.no_wait_gpu = false
8168c2ecf20Sopenharmony_ci	};
8178c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo;
8188c2ecf20Sopenharmony_ci	int ret;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	ret = ttm_bo_create(&dev_priv->bdev, bo_size,
8218c2ecf20Sopenharmony_ci			    ttm_bo_type_device,
8228c2ecf20Sopenharmony_ci			    &vmw_sys_ne_placement,
8238c2ecf20Sopenharmony_ci			    0, false, &bo);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (unlikely(ret != 0))
8268c2ecf20Sopenharmony_ci		return ret;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	ret = ttm_bo_reserve(bo, false, true, NULL);
8298c2ecf20Sopenharmony_ci	BUG_ON(ret != 0);
8308c2ecf20Sopenharmony_ci	ret = vmw_ttm_populate(bo->bdev, bo->ttm, &ctx);
8318c2ecf20Sopenharmony_ci	if (likely(ret == 0)) {
8328c2ecf20Sopenharmony_ci		struct vmw_ttm_tt *vmw_tt =
8338c2ecf20Sopenharmony_ci			container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
8348c2ecf20Sopenharmony_ci		ret = vmw_ttm_map_dma(vmw_tt);
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	ttm_bo_unreserve(bo);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (likely(ret == 0))
8408c2ecf20Sopenharmony_ci		*bo_p = bo;
8418c2ecf20Sopenharmony_ci	return ret;
8428c2ecf20Sopenharmony_ci}
843