Files
linux-nv-oot/drivers/misc/nvscic2c-pcie/iova-alloc.c
dbadgaiyan 55cee03ee7 drivers: misc: Fix coverity issues
Fix 2 coverity issues.
CID 10165044
CID 10165045

Bug 3952896

Change-Id: Ide19b44148c9e438284de45aa309c7cdc9e2d2e1
Signed-off-by: dbadgaiyan <dbadgaiyan@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2850604
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Arihant Jejani <ajejani@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-02-04 02:30:44 -08:00

139 lines
3.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#define pr_fmt(fmt) "nvscic2c-pcie: iova-alloc: " fmt
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "iova-alloc.h"
struct iova_alloc_domain_t {
struct device *dev;
struct iommu_domain *domain;
struct iova_domain iovad;
};
static int
iovad_init(struct device *dev, struct iova_alloc_domain_t **ivd_h)
{
int ret = 0;
dma_addr_t start = 0;
unsigned long order = 0;
struct iova_alloc_domain_t *ivd_ctx = NULL;
struct iommu_domain_geometry *geometry = NULL;
ivd_ctx = kzalloc(sizeof(*ivd_ctx), GFP_KERNEL);
if (WARN_ON(!ivd_ctx))
return -ENOMEM;
ivd_ctx->dev = dev;
ret = iova_cache_get();
if (ret < 0)
goto free_ivd;
ivd_ctx->domain = iommu_get_domain_for_dev(dev);
if (!ivd_ctx->domain) {
ret = -EINVAL;
pr_err("iommu_get_domain_for_dev() failed.\n");
goto put_cache;
}
geometry = &ivd_ctx->domain->geometry;
start = geometry->aperture_start & dev->coherent_dma_mask;
order = __ffs(ivd_ctx->domain->pgsize_bitmap);
pr_debug("Order of address allocation for IOVA domain: %lu\n", order);
init_iova_domain(&ivd_ctx->iovad, 1UL << order, start >> order);
*ivd_h = ivd_ctx;
return ret;
put_cache:
iova_cache_put();
free_ivd:
kfree(ivd_ctx);
return ret;
}
static void
iovad_deinit(struct iova_alloc_domain_t **ivd_h)
{
struct iova_alloc_domain_t *ivd_ctx = NULL;
ivd_ctx = (struct iova_alloc_domain_t *)(*ivd_h);
put_iova_domain(&ivd_ctx->iovad);
iova_cache_put();
kfree(ivd_ctx);
*ivd_h = NULL;
}
int
iova_alloc_init(struct device *dev, size_t size, dma_addr_t *dma_handle,
struct iova_alloc_domain_t **ivd_h)
{
int ret = 0;
unsigned long shift = 0U;
unsigned long iova = 0U;
unsigned long iova_len = 0U;
dma_addr_t dma_limit = 0x0;
struct iova_alloc_domain_t *ivd_ctx = NULL;
struct iommu_domain_geometry *geometry = NULL;
if (WARN_ON(!dev || !dma_handle || !ivd_h || *ivd_h))
return -EINVAL;
ret = iovad_init(dev, &ivd_ctx);
if (ret < 0) {
pr_err("Failed in allocating IOVA domain: %d\n", ret);
return ret;
}
geometry = &ivd_ctx->domain->geometry;
dma_limit = ivd_ctx->dev->coherent_dma_mask;
shift = iova_shift(&ivd_ctx->iovad);
iova_len = size >> shift;
/* Recommendation is to allocate in power of 2.*/
if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
iova_len = roundup_pow_of_two(iova_len);
if (*ivd_ctx->dev->dma_mask)
dma_limit &= *ivd_ctx->dev->dma_mask;
if (geometry->force_aperture)
dma_limit = min(dma_limit, geometry->aperture_end);
/* Try to get PCI devices a SAC address */
if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(ivd_ctx->dev))
iova = alloc_iova_fast(&ivd_ctx->iovad, iova_len,
DMA_BIT_MASK(32) >> shift, false);
if (!iova)
iova = alloc_iova_fast(&ivd_ctx->iovad, iova_len,
dma_limit >> shift, true);
*dma_handle = (dma_addr_t)iova << shift;
*ivd_h = ivd_ctx;
return ret;
}
void
iova_alloc_deinit(dma_addr_t dma_handle, size_t size,
struct iova_alloc_domain_t **ivd_h)
{
struct iova_domain *iovad = NULL;
struct iova_alloc_domain_t *ivd_ctx = NULL;
if (!ivd_h || !(*ivd_h) || !dma_handle)
return;
ivd_ctx = *ivd_h;
iovad = &ivd_ctx->iovad;
free_iova_fast(iovad, iova_pfn(iovad, dma_handle),
size >> iova_shift(iovad));
iovad_deinit(ivd_h);
}