static struct arm_lpae_io_pgtable * arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) { unsigned long va_bits, pgd_bits; struct arm_lpae_io_pgtable *data; arm_lpae_restrict_pgsizes(cfg); if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K | SZ_64K))) return NULL; if (cfg->ias > ARM_LPAE_MAX_ADDR_BITS) return NULL; if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS) return NULL; if (!selftest_running && cfg->iommu_dev->dma_pfn_offset) { dev_err(cfg->iommu_dev, "Cannot accommodate DMA offset for IOMMU page tables\n"); return NULL; } data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return NULL; data->pg_shift = __ffs(cfg->pgsize_bitmap); data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte)); va_bits = cfg->ias - data->pg_shift; data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level); /* Calculate the actual size of our pgd (without concatenation) */ pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1)); data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte))); data->iop.ops = (struct io_pgtable_ops) { .map = arm_lpae_map, .unmap = arm_lpae_unmap, .iova_to_phys = arm_lpae_iova_to_phys, }; return data; }
static struct arm_lpae_io_pgtable * arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) { unsigned long va_bits, pgd_bits; struct arm_lpae_io_pgtable *data; arm_lpae_restrict_pgsizes(cfg); if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K | SZ_64K))) return NULL; if (cfg->ias > ARM_LPAE_MAX_ADDR_BITS) return NULL; if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS) return NULL; data = vmm_zalloc(sizeof(*data)); if (!data) return NULL; data->pg_shift = __ffs(cfg->pgsize_bitmap); data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte)); va_bits = cfg->ias - data->pg_shift; data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level); /* Calculate the actual size of our pgd (without concatenation) */ pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1)); data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte))); data->iop.ops = (struct io_pgtable_ops) { .map = arm_lpae_map, .unmap = arm_lpae_unmap, .iova_to_phys = arm_lpae_iova_to_phys, }; return data; }