return NULL;
}
-static void __init reserve_iommu_exclusion_range(
- struct amd_iommu *iommu, uint64_t base, uint64_t limit)
+static int __init reserve_iommu_exclusion_range(
+ struct amd_iommu *iommu, uint64_t base, uint64_t limit,
+ bool all, bool iw, bool ir)
{
+ if ( !ir || !iw )
+ return -EPERM;
+
/* need to extend exclusion range? */
if ( iommu->exclusion_enable )
{
+ if ( iommu->exclusion_limit + PAGE_SIZE < base ||
+ limit + PAGE_SIZE < iommu->exclusion_base ||
+ iommu->exclusion_allow_all != all )
+ return -EBUSY;
+
if ( iommu->exclusion_base < base )
base = iommu->exclusion_base;
if ( iommu->exclusion_limit > limit )
}
iommu->exclusion_enable = IOMMU_CONTROL_ENABLED;
+ iommu->exclusion_allow_all = all;
iommu->exclusion_base = base;
iommu->exclusion_limit = limit;
-}
-static void __init reserve_iommu_exclusion_range_all(
- struct amd_iommu *iommu,
- unsigned long base, unsigned long limit)
-{
- reserve_iommu_exclusion_range(iommu, base, limit);
- iommu->exclusion_allow_all = IOMMU_CONTROL_ENABLED;
+ return 0;
}
static void __init reserve_unity_map_for_device(
unsigned long range_top, iommu_top, length;
struct amd_iommu *iommu;
unsigned int bdf;
+ int rc = 0;
/* is part of exclusion range inside of IOMMU virtual address space? */
/* note: 'limit' parameter is assumed to be page-aligned */
if ( limit >= iommu_top )
{
for_each_amd_iommu( iommu )
- reserve_iommu_exclusion_range_all(iommu, base, limit);
+ {
+ rc = reserve_iommu_exclusion_range(iommu, base, limit,
+ true /* all */, iw, ir);
+ if ( rc )
+ break;
+ }
}
- return 0;
+ return rc;
}
static int __init register_exclusion_range_for_device(
unsigned long range_top, iommu_top, length;
struct amd_iommu *iommu;
u16 req;
+ int rc = 0;
iommu = find_iommu_for_device(seg, bdf);
if ( !iommu )
/* register IOMMU exclusion range settings for device */
if ( limit >= iommu_top )
{
- reserve_iommu_exclusion_range(iommu, base, limit);
+ rc = reserve_iommu_exclusion_range(iommu, base, limit,
+ false /* all */, iw, ir);
ivrs_mappings[bdf].dte_allow_exclusion = IOMMU_CONTROL_ENABLED;
ivrs_mappings[req].dte_allow_exclusion = IOMMU_CONTROL_ENABLED;
}
- return 0;
+ return rc;
}
static int __init register_exclusion_range_for_iommu_devices(
unsigned long range_top, iommu_top, length;
unsigned int bdf;
u16 req;
+ int rc = 0;
/* is part of exclusion range inside of IOMMU virtual address space? */
/* note: 'limit' parameter is assumed to be page-aligned */
/* register IOMMU exclusion range settings */
if ( limit >= iommu_top )
- reserve_iommu_exclusion_range_all(iommu, base, limit);
- return 0;
+ rc = reserve_iommu_exclusion_range(iommu, base, limit,
+ true /* all */, iw, ir);
+
+ return rc;
}
static int __init parse_ivmd_device_select(