* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "dvt.h"
#include "kvmdt.h"
#include "vfio_ops.h"
* hw_dvt_hypervisor_inject_msix - inject a MSIX interrupt into vdavinci
*
* Returns:
* Zero on success, negative error code if failed.
*/
int hw_dvt_hypervisor_inject_msix(void *__vdavinci, u32 vector)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
u16 command, control;
int ret;
if (vdavinci == NULL) {
return -EINVAL;
}
command = *(u16 *)(&vdavinci_cfg_space(vdavinci)[PCI_COMMAND]);
control = *(u16 *)(&vdavinci_cfg_space(vdavinci)[DAVINCI_PCI_MSIX_FLAGS]);
if (!(command & PCI_COMMAND_INTX_DISABLE) ||
!(control & PCI_MSIX_FLAGS_ENABLE) ||
(control & PCI_MSIX_FLAGS_MASKALL)) {
vascend_info(vdavinci->dvt->vdavinci_priv->dev,
"hw_dvt_hypervisor_inject_msix failed, msix cap flag did't support\n");
return -EPERM;
}
ret = g_hw_kvmdt_ops.inject_msix(vdavinci->handle, vector);
if (ret)
return ret;
return 0;
}
* hw_dvt_hypervisor_read_gpa - copy data from GPA to host data buffer
* @vdavinci: a vdavinci
* @gpa: guest physical addr
* @buf: host data buffer
* @len: data length
*
* Returns:
* Zero on success, negative error code if failed.
*/
int hw_dvt_hypervisor_read_gpa(void *__vdavinci,
unsigned long gpa, void *buf, unsigned long len)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL || buf == NULL) {
return -EINVAL;
}
return g_hw_kvmdt_ops.read_gpa(vdavinci->handle, gpa, buf, len);
}
* hw_dvt_hypervisor_write_gpa - copy data from host data buffer to GPA
* @vdavinci: a vdavinci
* @gpa: guest physical addr
* @buf: host data buffer
* @len: data length
*
* Returns:
* Zero on success, negative error code if failed.
*/
int hw_dvt_hypervisor_write_gpa(void *__vdavinci,
unsigned long gpa, void *buf, unsigned long len)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL || buf == NULL) {
return -EINVAL;
}
return g_hw_kvmdt_ops.write_gpa(vdavinci->handle, gpa, buf, len);
}
* hw_dvt_hypervisor_gfn_to_mfn - translate a GFN to MFN
* @vdavinci: a vdavinci
* @gpfn: guest pfn
*
* Returns:
* MFN on success, hw_dvt_INVALID_ADDR if failed.
*/
unsigned long hw_dvt_hypervisor_gfn_to_mfn(void *__vdavinci, unsigned long gfn)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL) {
return ~0;
}
return g_hw_kvmdt_ops.gfn_to_mfn(vdavinci->handle, gfn);
}
* hw_dvt_hypervisor_dma_pool_init - dma pool init
* @vdavinci: a vdavinci
*
* Returns:
* 0 on success, negative error code if failed.
*/
int hw_dvt_hypervisor_dma_pool_init(void *__vdavinci)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL) {
return -EINVAL;
}
return g_hw_kvmdt_ops.dma_pool_init(vdavinci);
}
* hw_dvt_hypervisor_dma_pool_uninit - dma pool uninit
* @vdavinci: a vdavinci
*/
void hw_dvt_hypervisor_dma_pool_uninit(void *__vdavinci)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL) {
return;
}
g_hw_kvmdt_ops.dma_pool_uninit(vdavinci);
}
* hw_dvt_hypervisor_dma_map_guest_page - setup dma map for guest page
* @vdavinci: a vdavinci
* @gfn: guest pfn
* @size: page size
* @dma_sgt: retrieve allocated dma addr list(sg_table)
*
* Returns:
* 0 on success, negative error code if failed.
*/
int hw_dvt_hypervisor_dma_map_guest_page(void *__vdavinci,
unsigned long gfn, unsigned long size,
struct sg_table **dma_sgt)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL || dma_sgt == NULL) {
return -EINVAL;
}
return g_hw_kvmdt_ops.dma_get_iova(vdavinci, gfn, size, dma_sgt);
}
* hw_dvt_hypervisor_dma_unmap_guest_page - cancel dma map for guest page
* @vdavinci: a vdavinci
* @dma_sgt: the dma addr list(sg_table)
*/
void hw_dvt_hypervisor_dma_unmap_guest_page(void *__vdavinci,
struct sg_table *dma_sgt)
{
if (__vdavinci == NULL || dma_sgt == NULL) {
pr_err("vdavinci or dma_sgt is null\n");
return;
}
return g_hw_kvmdt_ops.dma_put_iova(dma_sgt);
}
* hw_dvt_hypervisor_dma_pool_active - dma pool active or not
* @__vdavinci: a vdavinci
*
* Returns:
* true on active, false on inactive.
*/
bool hw_dvt_hypervisor_dma_pool_active(void *__vdavinci)
{
if (__vdavinci == NULL) {
return false;
}
return true;
}
* hw_dvt_hypervisor_dma_map_guest_page_batch
* - setup dma map for guest page when dma pool is active
* @__vdavinci: a vdavinci
* @gfn: guest pfn array
* @dma_addr: retrieve dma addr array
* @count: array size
*
* Returns:
* 0 on success, negative error code if failed.
*/
int hw_dvt_hypervisor_dma_map_guest_page_batch(void *__vdavinci,
unsigned long *gfn, unsigned long *dma_addr, unsigned long count)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL || gfn == NULL || dma_addr == NULL
|| count == 0) {
return -EINVAL;
}
return g_hw_kvmdt_ops.dma_get_iova_batch(vdavinci, gfn, dma_addr, count);
}
* hw_dvt_hypervisor_dma_unmap_guest_page_batch
* - cancel dma map for guest page when dma pool is active
* @__vdavinci: a vdavinci
* @gfn: guest pfn array
* @dma_addr: retrieve dma addr array
* @count: array size
*/
void hw_dvt_hypervisor_dma_unmap_guest_page_batch(void *__vdavinci, unsigned long *gfn,
unsigned long *dma_addr, unsigned long count)
{
}
* hw_dvt_hypervisor_is_valid_gfn - check if a visible gfn
* @vdavinci: a vdavinci
* @gfn: guest PFN
*
* Returns:
* true on valid gfn, false on not.
*/
bool hw_dvt_hypervisor_is_valid_gfn(void *__vdavinci, unsigned long gfn)
{
struct hw_vdavinci *vdavinci = (struct hw_vdavinci *)__vdavinci;
if (vdavinci == NULL) {
return false;
}
if (g_hw_kvmdt_ops.is_valid_gfn == NULL) {
return true;
}
return g_hw_kvmdt_ops.is_valid_gfn(vdavinci->handle, gfn);
}
int hw_dvt_hypervisor_mmio_get(void **dst, int *size, void *__vdavinci, int bar)
{
if (g_hw_kvmdt_ops.mmio_get == NULL || __vdavinci == NULL ||
dst == NULL || size == NULL) {
return -EINVAL;
}
return g_hw_kvmdt_ops.mmio_get(dst, size, __vdavinci, bar);
}