162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "vmwgfx_drv.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define VMW_PPN_SIZE (sizeof(unsigned long)) 3262306a36Sopenharmony_ci/* A future safe maximum remap size. */ 3362306a36Sopenharmony_ci#define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE) 3462306a36Sopenharmony_ci#define DMA_ADDR_INVALID ((dma_addr_t) 0) 3562306a36Sopenharmony_ci#define DMA_PAGE_INVALID 0UL 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int vmw_gmr2_bind(struct vmw_private *dev_priv, 3862306a36Sopenharmony_ci struct vmw_piter *iter, 3962306a36Sopenharmony_ci unsigned long num_pages, 4062306a36Sopenharmony_ci int gmr_id) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci SVGAFifoCmdDefineGMR2 define_cmd; 4362306a36Sopenharmony_ci SVGAFifoCmdRemapGMR2 remap_cmd; 4462306a36Sopenharmony_ci uint32_t *cmd; 4562306a36Sopenharmony_ci uint32_t *cmd_orig; 4662306a36Sopenharmony_ci uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd); 4762306a36Sopenharmony_ci uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0); 4862306a36Sopenharmony_ci uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num; 4962306a36Sopenharmony_ci uint32_t remap_pos = 0; 5062306a36Sopenharmony_ci uint32_t cmd_size = define_size + remap_size; 5162306a36Sopenharmony_ci uint32_t i; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci cmd_orig = cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); 5462306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci define_cmd.gmrId = gmr_id; 5862306a36Sopenharmony_ci define_cmd.numPages = num_pages; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci *cmd++ = SVGA_CMD_DEFINE_GMR2; 6162306a36Sopenharmony_ci memcpy(cmd, &define_cmd, sizeof(define_cmd)); 6262306a36Sopenharmony_ci cmd += sizeof(define_cmd) / sizeof(*cmd); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * Need to split the command if there are too many 6662306a36Sopenharmony_ci * pages that goes into the gmr. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci remap_cmd.gmrId = gmr_id; 7062306a36Sopenharmony_ci remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ? 7162306a36Sopenharmony_ci SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci while (num_pages > 0) { 7462306a36Sopenharmony_ci unsigned long nr = min_t(unsigned long, num_pages, VMW_PPN_PER_REMAP); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci remap_cmd.offsetPages = remap_pos; 7762306a36Sopenharmony_ci remap_cmd.numPages = nr; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci *cmd++ = SVGA_CMD_REMAP_GMR2; 8062306a36Sopenharmony_ci memcpy(cmd, &remap_cmd, sizeof(remap_cmd)); 8162306a36Sopenharmony_ci cmd += sizeof(remap_cmd) / sizeof(*cmd); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci for (i = 0; i < nr; ++i) { 8462306a36Sopenharmony_ci if (VMW_PPN_SIZE <= 4) 8562306a36Sopenharmony_ci *cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT; 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci *((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >> 8862306a36Sopenharmony_ci PAGE_SHIFT; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci cmd += VMW_PPN_SIZE / sizeof(*cmd); 9162306a36Sopenharmony_ci vmw_piter_next(iter); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci num_pages -= nr; 9562306a36Sopenharmony_ci remap_pos += nr; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd)); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, cmd_size); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void vmw_gmr2_unbind(struct vmw_private *dev_priv, 10662306a36Sopenharmony_ci int gmr_id) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci SVGAFifoCmdDefineGMR2 define_cmd; 10962306a36Sopenharmony_ci uint32_t define_size = sizeof(define_cmd) + 4; 11062306a36Sopenharmony_ci uint32_t *cmd; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, define_size); 11362306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci define_cmd.gmrId = gmr_id; 11762306a36Sopenharmony_ci define_cmd.numPages = 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci *cmd++ = SVGA_CMD_DEFINE_GMR2; 12062306a36Sopenharmony_ci memcpy(cmd, &define_cmd, sizeof(define_cmd)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, define_size); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint vmw_gmr_bind(struct vmw_private *dev_priv, 12762306a36Sopenharmony_ci const struct vmw_sg_table *vsgt, 12862306a36Sopenharmony_ci unsigned long num_pages, 12962306a36Sopenharmony_ci int gmr_id) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct vmw_piter data_iter; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci vmw_piter_start(&data_iter, vsgt, 0); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (unlikely(!vmw_piter_next(&data_iter))) 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2))) 13962306a36Sopenharmony_ci return -EINVAL; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_civoid vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) 14862306a36Sopenharmony_ci vmw_gmr2_unbind(dev_priv, gmr_id); 14962306a36Sopenharmony_ci} 150