hv:vtd: fix MISRA-C violations on procedure has more than one exit point

This patch fix MISRA-C violations in arch/x86/vtd.c
on Procedure has more than one exit point.

Tracked-On: #861
Signed-off-by: Tw <wei.tan@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Tw 2018-12-20 09:50:30 +08:00 committed by wenlingz
parent a98a1a690c
commit 60f78e1e70

View File

@ -177,15 +177,12 @@ static int32_t register_hrhd_units(void)
if ((info == NULL) || (info->drhd_count == 0U)) { if ((info == NULL) || (info->drhd_count == 0U)) {
pr_fatal("%s: can't find dmar info\n", __func__); pr_fatal("%s: can't find dmar info\n", __func__);
return -ENODEV; ret = -ENODEV;
} } else if (info->drhd_count > CONFIG_MAX_IOMMU_NUM) {
if (info->drhd_count > CONFIG_MAX_IOMMU_NUM) {
pr_fatal("%s: dmar count(%d) beyond the limitation(%d)\n", pr_fatal("%s: dmar count(%d) beyond the limitation(%d)\n",
__func__, info->drhd_count, CONFIG_MAX_IOMMU_NUM); __func__, info->drhd_count, CONFIG_MAX_IOMMU_NUM);
return -EINVAL; ret = -EINVAL;
} } else {
for (i = 0U; i < info->drhd_count; i++) { for (i = 0U; i < info->drhd_count; i++) {
drhd_rt = &dmar_drhd_units[i]; drhd_rt = &dmar_drhd_units[i];
drhd_rt->index = i; drhd_rt->index = i;
@ -193,11 +190,12 @@ static int32_t register_hrhd_units(void)
drhd_rt->dmar_irq = IRQ_INVALID; drhd_rt->dmar_irq = IRQ_INVALID;
ret = dmar_register_hrhd(drhd_rt); ret = dmar_register_hrhd(drhd_rt);
if (ret != 0) { if (ret != 0) {
return ret; break;
}
} }
} }
return 0; return ret;
} }
static uint32_t iommu_read32(const struct dmar_drhd_rt *dmar_unit, uint32_t offset) static uint32_t iommu_read32(const struct dmar_drhd_rt *dmar_unit, uint32_t offset)
@ -392,6 +390,8 @@ static void dmar_disable_translation(struct dmar_drhd_rt *dmar_unit)
static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit) static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit)
{ {
int32_t ret = 0;
dev_dbg(ACRN_DBG_IOMMU, "Register dmar uint [%d] @0x%llx", dmar_unit->index, dmar_unit->drhd->reg_base_addr); dev_dbg(ACRN_DBG_IOMMU, "Register dmar uint [%d] @0x%llx", dmar_unit->index, dmar_unit->drhd->reg_base_addr);
spinlock_init(&dmar_unit->lock); spinlock_init(&dmar_unit->lock);
@ -418,14 +418,11 @@ static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit)
/* check capability */ /* check capability */
if ((iommu_cap_super_page_val(dmar_unit->cap) & 0x1U) == 0U) { if ((iommu_cap_super_page_val(dmar_unit->cap) & 0x1U) == 0U) {
pr_fatal("%s: dmar uint doesn't support 2MB page!\n", __func__); pr_fatal("%s: dmar uint doesn't support 2MB page!\n", __func__);
return -ENODEV; ret = -ENODEV;
} } else if ((iommu_cap_super_page_val(dmar_unit->cap) & 0x2U) == 0U) {
if ((iommu_cap_super_page_val(dmar_unit->cap) & 0x2U) == 0U) {
pr_fatal("%s: dmar uint doesn't support 1GB page!\n", __func__); pr_fatal("%s: dmar uint doesn't support 1GB page!\n", __func__);
return -ENODEV; ret = -ENODEV;
} } else {
if ((iommu_ecap_c(dmar_unit->ecap) == 0U) && (dmar_unit->drhd->ignore != 0U)) { if ((iommu_ecap_c(dmar_unit->ecap) == 0U) && (dmar_unit->drhd->ignore != 0U)) {
iommu_page_walk_coherent = false; iommu_page_walk_coherent = false;
} }
@ -441,16 +438,20 @@ static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit)
} }
dmar_disable_translation(dmar_unit); dmar_disable_translation(dmar_unit);
}
return 0; return ret;
} }
static struct dmar_drhd_rt *device_to_dmaru(uint16_t segment, uint8_t bus, uint8_t devfun) static struct dmar_drhd_rt *device_to_dmaru(uint16_t segment, uint8_t bus, uint8_t devfun)
{ {
struct dmar_info *info = get_dmar_info(); struct dmar_info *info = get_dmar_info();
struct dmar_drhd_rt *dmar_unit; struct dmar_drhd_rt *dmar_unit = NULL;
uint32_t i, j; uint32_t i, j;
if (info == NULL) {
pr_fatal("%s: can't find dmar info\n", __func__);
} else {
for (j = 0U; j < info->drhd_count; j++) { for (j = 0U; j < info->drhd_count; j++) {
dmar_unit = &dmar_drhd_units[j]; dmar_unit = &dmar_drhd_units[j];
@ -461,17 +462,28 @@ static struct dmar_drhd_rt *device_to_dmaru(uint16_t segment, uint8_t bus, uint8
for (i = 0U; i < dmar_unit->drhd->dev_cnt; i++) { for (i = 0U; i < dmar_unit->drhd->dev_cnt; i++) {
if ((dmar_unit->drhd->devices[i].bus == bus) && if ((dmar_unit->drhd->devices[i].bus == bus) &&
(dmar_unit->drhd->devices[i].devfun == devfun)) { (dmar_unit->drhd->devices[i].devfun == devfun)) {
return dmar_unit; break;
} }
} }
/* find exact one */
if (i != dmar_unit->drhd->dev_cnt) {
break;
}
/* has the same segment number and the dmar unit has INCLUDE_PCI_ALL set */ /* has the same segment number and the dmar unit has INCLUDE_PCI_ALL set */
if ((dmar_unit->drhd->flags & DRHD_FLAG_INCLUDE_PCI_ALL_MASK) != 0U) { if ((dmar_unit->drhd->flags & DRHD_FLAG_INCLUDE_PCI_ALL_MASK) != 0U) {
return dmar_unit; break;
} }
} }
return NULL; /* not found */
if (j == info->drhd_count) {
dmar_unit = NULL;
}
}
return dmar_unit;
} }
static void dmar_write_buffer_flush(struct dmar_drhd_rt *dmar_unit) static void dmar_write_buffer_flush(struct dmar_drhd_rt *dmar_unit)
@ -511,10 +523,12 @@ static void dmar_invalid_context_cache(struct dmar_drhd_rt *dmar_unit,
cmd |= DMA_CCMD_DEVICE_INVL | dma_ccmd_did(did) | dma_ccmd_sid(sid) | dma_ccmd_fm(fm); cmd |= DMA_CCMD_DEVICE_INVL | dma_ccmd_did(did) | dma_ccmd_sid(sid) | dma_ccmd_fm(fm);
break; break;
default: default:
cmd = 0UL;
pr_err("unknown CIRG type"); pr_err("unknown CIRG type");
return; break;
} }
if (cmd != 0UL) {
spinlock_obtain(&(dmar_unit->lock)); spinlock_obtain(&(dmar_unit->lock));
iommu_write64(dmar_unit, DMAR_CCMD_REG, cmd); iommu_write64(dmar_unit, DMAR_CCMD_REG, cmd);
/* read upper 32bits to check */ /* read upper 32bits to check */
@ -523,6 +537,7 @@ static void dmar_invalid_context_cache(struct dmar_drhd_rt *dmar_unit,
spinlock_release(&(dmar_unit->lock)); spinlock_release(&(dmar_unit->lock));
dev_dbg(ACRN_DBG_IOMMU, "cc invalidation granularity %d", dma_ccmd_get_caig_32(status)); dev_dbg(ACRN_DBG_IOMMU, "cc invalidation granularity %d", dma_ccmd_get_caig_32(status));
}
} }
static void dmar_invalid_context_cache_global(struct dmar_drhd_rt *dmar_unit) static void dmar_invalid_context_cache_global(struct dmar_drhd_rt *dmar_unit)
@ -555,9 +570,11 @@ static void dmar_invalid_iotlb(struct dmar_drhd_rt *dmar_unit, uint16_t did, uin
} }
break; break;
default: default:
cmd = 0UL;
pr_err("unknown IIRG type"); pr_err("unknown IIRG type");
return;
} }
if (cmd != 0UL) {
spinlock_obtain(&(dmar_unit->lock)); spinlock_obtain(&(dmar_unit->lock));
if (addr != 0U) { if (addr != 0U) {
iommu_write64(dmar_unit, dmar_unit->ecap_iotlb_offset, addr); iommu_write64(dmar_unit, dmar_unit->ecap_iotlb_offset, addr);
@ -571,6 +588,7 @@ static void dmar_invalid_iotlb(struct dmar_drhd_rt *dmar_unit, uint16_t did, uin
if (dma_iotlb_get_iaig_32(status) == 0U) { if (dma_iotlb_get_iaig_32(status) == 0U) {
pr_err("fail to invalidate IOTLB!, 0x%x, 0x%x", status, iommu_read32(dmar_unit, DMAR_FSTS_REG)); pr_err("fail to invalidate IOTLB!, 0x%x, 0x%x", status, iommu_read32(dmar_unit, DMAR_FSTS_REG));
} }
}
} }
/* Invalidate IOTLB globally, /* Invalidate IOTLB globally,
@ -833,23 +851,18 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
uint64_t upper; uint64_t upper;
uint64_t lower = 0UL; uint64_t lower = 0UL;
struct acrn_vm *vm; struct acrn_vm *vm;
int32_t ret = 0;
dmar_unit = device_to_dmaru(segment, bus, devfun); dmar_unit = device_to_dmaru(segment, bus, devfun);
if (dmar_unit == NULL) { if (dmar_unit == NULL) {
pr_err("no dmar unit found for device: %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun)); pr_err("no dmar unit found for device: %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun));
return -EINVAL; ret = -EINVAL;
} } else if (dmar_unit->drhd->ignore) {
if (dmar_unit->drhd->ignore) {
dev_dbg(ACRN_DBG_IOMMU, "device is ignored :0x%x:%x.%x", bus, pci_slot(devfun), pci_func(devfun)); dev_dbg(ACRN_DBG_IOMMU, "device is ignored :0x%x:%x.%x", bus, pci_slot(devfun), pci_func(devfun));
return 0; } else if (!dmar_unit_support_aw(dmar_unit, domain->addr_width) || (dmar_unit->root_table_addr == 0UL)) {
} pr_err("invalid dmar unit");
ret = -EINVAL;
if (!dmar_unit_support_aw(dmar_unit, domain->addr_width)) { } else {
pr_err("dmar doesn't support addr width %d", domain->addr_width);
return -EINVAL;
}
if (iommu_ecap_sc(dmar_unit->ecap) == 0U) { if (iommu_ecap_sc(dmar_unit->ecap) == 0U) {
vm = get_vm_from_vmid(domain->vm_id); vm = get_vm_from_vmid(domain->vm_id);
if (vm != NULL) { if (vm != NULL) {
@ -860,11 +873,6 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
dev_dbg(ACRN_DBG_IOMMU, "vm=%d add %x:%x no snoop control!", domain->vm_id, bus, devfun); dev_dbg(ACRN_DBG_IOMMU, "vm=%d add %x:%x no snoop control!", domain->vm_id, bus, devfun);
} }
if (dmar_unit->root_table_addr == 0UL){
pr_err("dmar root table address invalid");
return -EINVAL;
}
root_table = (struct dmar_root_entry *)hpa2hva(dmar_unit->root_table_addr); root_table = (struct dmar_root_entry *)hpa2hva(dmar_unit->root_table_addr);
root_entry = root_table + bus; root_entry = root_table + bus;
@ -895,13 +903,15 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
context = (struct dmar_context_entry *)hpa2hva(context_table_addr); context = (struct dmar_context_entry *)hpa2hva(context_table_addr);
context_entry = context + devfun; context_entry = context + devfun;
if (context_entry == NULL) {
pr_err("dmar context entry is invalid");
ret = -EINVAL;
} else if (dmar_get_bitslice(context_entry->lower, CTX_ENTRY_LOWER_P_MASK, CTX_ENTRY_LOWER_P_POS) != 0UL) {
/* the context entry should not be present */ /* the context entry should not be present */
if (dmar_get_bitslice(context_entry->lower, CTX_ENTRY_LOWER_P_MASK, CTX_ENTRY_LOWER_P_POS) != 0UL) {
pr_err("%s: context entry@0x%llx (Lower:%x) ", __func__, context_entry, context_entry->lower); pr_err("%s: context entry@0x%llx (Lower:%x) ", __func__, context_entry, context_entry->lower);
pr_err("already present for %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun)); pr_err("already present for %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun));
return -EBUSY; ret = -EBUSY;
} } else {
/* setup context entry for the devfun */ /* setup context entry for the devfun */
upper = 0UL; upper = 0UL;
lower = 0UL; lower = 0UL;
@ -918,7 +928,7 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
CTX_ENTRY_LOWER_TT_MASK, CTX_ENTRY_LOWER_TT_POS, DMAR_CTX_TT_PASSTHROUGH); CTX_ENTRY_LOWER_TT_MASK, CTX_ENTRY_LOWER_TT_POS, DMAR_CTX_TT_PASSTHROUGH);
} else { } else {
pr_err("dmaru[%d] doesn't support trans passthrough", dmar_unit->index); pr_err("dmaru[%d] doesn't support trans passthrough", dmar_unit->index);
return -ENODEV; ret = -ENODEV;
} }
} else { } else {
/* TODO: add Device TLB support */ /* TODO: add Device TLB support */
@ -928,6 +938,7 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
CTX_ENTRY_LOWER_TT_MASK, CTX_ENTRY_LOWER_TT_POS, DMAR_CTX_TT_UNTRANSLATED); CTX_ENTRY_LOWER_TT_MASK, CTX_ENTRY_LOWER_TT_POS, DMAR_CTX_TT_UNTRANSLATED);
} }
if (ret == 0) {
upper = dmar_set_bitslice(upper, upper = dmar_set_bitslice(upper,
CTX_ENTRY_UPPER_DID_MASK, CTX_ENTRY_UPPER_DID_POS, (uint64_t)vmid_to_domainid(domain->vm_id)); CTX_ENTRY_UPPER_DID_MASK, CTX_ENTRY_UPPER_DID_POS, (uint64_t)vmid_to_domainid(domain->vm_id));
lower = dmar_set_bitslice(lower, lower = dmar_set_bitslice(lower,
@ -937,8 +948,11 @@ static int32_t add_iommu_device(struct iommu_domain *domain, uint16_t segment, u
context_entry->upper = upper; context_entry->upper = upper;
context_entry->lower = lower; context_entry->lower = lower;
iommu_flush_cache(dmar_unit, context_entry, sizeof(struct dmar_context_entry)); iommu_flush_cache(dmar_unit, context_entry, sizeof(struct dmar_context_entry));
}
}
}
return 0; return ret;
} }
static int32_t remove_iommu_device(const struct iommu_domain *domain, uint16_t segment, uint8_t bus, uint8_t devfun) static int32_t remove_iommu_device(const struct iommu_domain *domain, uint16_t segment, uint8_t bus, uint8_t devfun)
@ -949,29 +963,33 @@ static int32_t remove_iommu_device(const struct iommu_domain *domain, uint16_t s
struct dmar_context_entry *context; struct dmar_context_entry *context;
struct dmar_root_entry *root_entry; struct dmar_root_entry *root_entry;
struct dmar_context_entry *context_entry; struct dmar_context_entry *context_entry;
uint16_t dom_id; int32_t ret = 0;
dmar_unit = device_to_dmaru(segment, bus, devfun); dmar_unit = device_to_dmaru(segment, bus, devfun);
if (dmar_unit == NULL) { if (dmar_unit == NULL) {
pr_err("no dmar unit found for device: %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun)); pr_err("no dmar unit found for device: %x:%x.%x", bus, pci_slot(devfun), pci_func(devfun));
return -EINVAL; ret = -EINVAL;
} } else {
root_table = (struct dmar_root_entry *)hpa2hva(dmar_unit->root_table_addr); root_table = (struct dmar_root_entry *)hpa2hva(dmar_unit->root_table_addr);
root_entry = root_table + bus; root_entry = root_table + bus;
if (root_entry == NULL) {
pr_err("dmar root table entry is invalid\n");
ret = -EINVAL;
} else {
context_table_addr = dmar_get_bitslice(root_entry->lower, ROOT_ENTRY_LOWER_CTP_MASK, ROOT_ENTRY_LOWER_CTP_POS); context_table_addr = dmar_get_bitslice(root_entry->lower, ROOT_ENTRY_LOWER_CTP_MASK, ROOT_ENTRY_LOWER_CTP_POS);
context_table_addr = context_table_addr << PAGE_SHIFT; context_table_addr = context_table_addr << PAGE_SHIFT;
context = (struct dmar_context_entry *)hpa2hva(context_table_addr); context = (struct dmar_context_entry *)hpa2hva(context_table_addr);
context_entry = context + devfun; context_entry = context + devfun;
dom_id = (uint16_t)dmar_get_bitslice(context_entry->upper, CTX_ENTRY_UPPER_DID_MASK, CTX_ENTRY_UPPER_DID_POS); if (context_entry == NULL) {
if (dom_id != vmid_to_domainid(domain->vm_id)) { pr_err("dmar context entry is invalid");
ret = -EINVAL;
} else if ((uint16_t)dmar_get_bitslice(context_entry->upper, CTX_ENTRY_UPPER_DID_MASK, CTX_ENTRY_UPPER_DID_POS) != vmid_to_domainid(domain->vm_id)) {
pr_err("%s: domain id mismatch", __func__); pr_err("%s: domain id mismatch", __func__);
return -EPERM; ret = -EPERM;
} } else {
/* clear the present bit first */ /* clear the present bit first */
context_entry->lower = 0UL; context_entry->lower = 0UL;
context_entry->upper = 0UL; context_entry->upper = 0UL;
@ -979,7 +997,10 @@ static int32_t remove_iommu_device(const struct iommu_domain *domain, uint16_t s
dmar_invalid_context_cache_global(dmar_unit); dmar_invalid_context_cache_global(dmar_unit);
dmar_invalid_iotlb_global(dmar_unit); dmar_invalid_iotlb_global(dmar_unit);
return 0; }
}
}
return ret;
} }
/* /*
@ -992,9 +1013,7 @@ static void do_action_for_iommus(void (*action)(struct dmar_drhd_rt *))
struct dmar_drhd_rt *dmar_unit; struct dmar_drhd_rt *dmar_unit;
uint32_t i; uint32_t i;
if (info == NULL) { if (info != NULL) {
pr_fatal("%s: can't find dmar info\n", __func__);
} else {
for (i = 0U; i < info->drhd_count; i++) { for (i = 0U; i < info->drhd_count; i++) {
dmar_unit = &dmar_drhd_units[i]; dmar_unit = &dmar_drhd_units[i];
if (!dmar_unit->drhd->ignore) { if (!dmar_unit->drhd->ignore) {
@ -1003,6 +1022,8 @@ static void do_action_for_iommus(void (*action)(struct dmar_drhd_rt *))
dev_dbg(ACRN_DBG_IOMMU, "ignore dmar_unit @0x%x", dmar_unit->drhd->reg_base_addr); dev_dbg(ACRN_DBG_IOMMU, "ignore dmar_unit @0x%x", dmar_unit->drhd->reg_base_addr);
} }
} }
} else {
pr_fatal("%s: can't find dmar info\n", __func__);
} }
} }
@ -1059,12 +1080,13 @@ int32_t assign_iommu_device(struct iommu_domain *domain, uint8_t bus, uint8_t de
if (vm0_domain != NULL) { if (vm0_domain != NULL) {
status = remove_iommu_device(vm0_domain, 0U, bus, devfun); status = remove_iommu_device(vm0_domain, 0U, bus, devfun);
if (status != 0) {
return status;
}
} }
return add_iommu_device(domain, 0U, bus, devfun); if (status == 0) {
status = add_iommu_device(domain, 0U, bus, devfun);
}
return status;
} }
int32_t unassign_iommu_device(const struct iommu_domain *domain, uint8_t bus, uint8_t devfun) int32_t unassign_iommu_device(const struct iommu_domain *domain, uint8_t bus, uint8_t devfun)
@ -1073,15 +1095,12 @@ int32_t unassign_iommu_device(const struct iommu_domain *domain, uint8_t bus, ui
/* TODO: check if the device assigned */ /* TODO: check if the device assigned */
status = remove_iommu_device(domain, 0U, bus, devfun); status = remove_iommu_device(domain, 0U, bus, devfun);
if (status != 0) {
if ((status == 0) && (vm0_domain != NULL)) {
status = add_iommu_device(vm0_domain, 0U, bus, devfun);
}
return status; return status;
}
if (vm0_domain != NULL) {
return add_iommu_device(vm0_domain, 0U, bus, devfun);
}
return 0;
} }
void enable_iommu(void) void enable_iommu(void)
@ -1109,14 +1128,11 @@ void resume_iommu(void)
int32_t init_iommu(void) int32_t init_iommu(void)
{ {
int32_t ret; int32_t ret = 0;
ret = register_hrhd_units(); ret = register_hrhd_units();
if (ret != 0) { if (ret == 0) {
return ret;
} else {
do_action_for_iommus(dmar_prepare); do_action_for_iommus(dmar_prepare);
ret = 0;
} }
return ret; return ret;
@ -1130,7 +1146,9 @@ void init_iommu_vm0_domain(struct acrn_vm *vm0)
vm0->iommu = create_iommu_domain(vm0->vm_id, hva2hpa(vm0->arch_vm.nworld_eptp), 48U); vm0->iommu = create_iommu_domain(vm0->vm_id, hva2hpa(vm0->arch_vm.nworld_eptp), 48U);
vm0_domain = (struct iommu_domain *) vm0->iommu; vm0_domain = (struct iommu_domain *) vm0->iommu;
if (vm0_domain == NULL) {
pr_err("vm0 domain is NULL\n");
} else {
for (bus = 0U; bus < CONFIG_IOMMU_BUS_NUM; bus++) { for (bus = 0U; bus < CONFIG_IOMMU_BUS_NUM; bus++) {
for (devfun = 0U; devfun <= 255U; devfun++) { for (devfun = 0U; devfun <= 255U; devfun++) {
if (add_iommu_device(vm0_domain, 0U, (uint8_t)bus, (uint8_t)devfun) != 0) { if (add_iommu_device(vm0_domain, 0U, (uint8_t)bus, (uint8_t)devfun) != 0) {
@ -1139,4 +1157,5 @@ void init_iommu_vm0_domain(struct acrn_vm *vm0)
} }
} }
} }
}
} }