static bool copy_device_table()

in amd/init.c [922:1020]


static bool copy_device_table(void)
{
	u64 int_ctl, int_tab_len, entry = 0, last_entry = 0;
	struct dev_table_entry *old_devtb = NULL;
	u32 lo, hi, devid, old_devtb_size;
	phys_addr_t old_devtb_phys;
	struct amd_iommu *iommu;
	u16 dom_id, dte_v, irq_v;
	gfp_t gfp_flag;
	u64 tmp;

	if (!amd_iommu_pre_enabled)
		return false;

	pr_warn("Translation is already enabled - trying to copy translation structures\n");
	for_each_iommu(iommu) {
		/* All IOMMUs should use the same device table with the same size */
		lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
		hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
		entry = (((u64) hi) << 32) + lo;
		if (last_entry && last_entry != entry) {
			pr_err("IOMMU:%d should use the same dev table as others!\n",
				iommu->index);
			return false;
		}
		last_entry = entry;

		old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
		if (old_devtb_size != dev_table_size) {
			pr_err("The device table size of IOMMU:%d is not expected!\n",
				iommu->index);
			return false;
		}
	}

	/*
	 * When SME is enabled in the first kernel, the entry includes the
	 * memory encryption mask(sme_me_mask), we must remove the memory
	 * encryption mask to obtain the true physical address in kdump kernel.
	 */
	old_devtb_phys = __sme_clr(entry) & PAGE_MASK;

	if (old_devtb_phys >= 0x100000000ULL) {
		pr_err("The address of old device table is above 4G, not trustworthy!\n");
		return false;
	}
	old_devtb = (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT) && is_kdump_kernel())
		    ? (__force void *)ioremap_encrypted(old_devtb_phys,
							dev_table_size)
		    : memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);

	if (!old_devtb)
		return false;

	gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
	old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
				get_order(dev_table_size));
	if (old_dev_tbl_cpy == NULL) {
		pr_err("Failed to allocate memory for copying old device table!\n");
		return false;
	}

	for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
		old_dev_tbl_cpy[devid] = old_devtb[devid];
		dom_id = old_devtb[devid].data[1] & DEV_DOMID_MASK;
		dte_v = old_devtb[devid].data[0] & DTE_FLAG_V;

		if (dte_v && dom_id) {
			old_dev_tbl_cpy[devid].data[0] = old_devtb[devid].data[0];
			old_dev_tbl_cpy[devid].data[1] = old_devtb[devid].data[1];
			__set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
			/* If gcr3 table existed, mask it out */
			if (old_devtb[devid].data[0] & DTE_FLAG_GV) {
				tmp = DTE_GCR3_VAL_B(~0ULL) << DTE_GCR3_SHIFT_B;
				tmp |= DTE_GCR3_VAL_C(~0ULL) << DTE_GCR3_SHIFT_C;
				old_dev_tbl_cpy[devid].data[1] &= ~tmp;
				tmp = DTE_GCR3_VAL_A(~0ULL) << DTE_GCR3_SHIFT_A;
				tmp |= DTE_FLAG_GV;
				old_dev_tbl_cpy[devid].data[0] &= ~tmp;
			}
		}

		irq_v = old_devtb[devid].data[2] & DTE_IRQ_REMAP_ENABLE;
		int_ctl = old_devtb[devid].data[2] & DTE_IRQ_REMAP_INTCTL_MASK;
		int_tab_len = old_devtb[devid].data[2] & DTE_INTTABLEN_MASK;
		if (irq_v && (int_ctl || int_tab_len)) {
			if ((int_ctl != DTE_IRQ_REMAP_INTCTL) ||
			    (int_tab_len != DTE_INTTABLEN)) {
				pr_err("Wrong old irq remapping flag: %#x\n", devid);
				return false;
			}

		        old_dev_tbl_cpy[devid].data[2] = old_devtb[devid].data[2];
		}
	}
	memunmap(old_devtb);

	return true;
}