Commit 6af67f2d authored by Shivaprasad G Bhat's avatar Shivaprasad G Bhat Committed by Michael Ellerman
Browse files

powerpc/pseries/iommu: Fix the VFIO_IOMMU_SPAPR_TCE_GET_INFO ioctl output



The ioctl VFIO_IOMMU_SPAPR_TCE_GET_INFO is not reporting the
actuals on the platform as not all the details are correctly
collected during the platform probe/scan into the iommu_table_group.

Collect the information during the device setup time as the DMA
window property is already looked up on parent nodes anyway.

Signed-off-by: default avatarShivaprasad G Bhat <sbhat@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/171923271138.1397.7908302630061814623.stgit@linux.ibm.com
parent b09c031d
Loading
Loading
Loading
Loading
+67 −14
Original line number Diff line number Diff line
@@ -865,13 +865,6 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
				be32_to_cpu(prop.tce_shift), NULL,
				&iommu_table_lpar_multi_ops);

		/* Only for normal boot with default window. Doesn't matter even
		 * if we set these with DDW which is 64bit during kdump, since
		 * these will not be used during kdump.
		 */
		ppci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
		ppci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);

		if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
			panic("Failed to initialize iommu table");

@@ -1658,6 +1651,71 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
	return direct_mapping;
}

static __u64 query_page_size_to_mask(u32 query_page_size)
{
	const long shift[] = {
		(SZ_4K),   (SZ_64K), (SZ_16M),
		(SZ_32M),  (SZ_64M), (SZ_128M),
		(SZ_256M), (SZ_16G), (SZ_2M)
	};
	int i, ret = 0;

	for (i = 0; i < ARRAY_SIZE(shift); i++) {
		if (query_page_size & (1 << i))
			ret |= shift[i];
	}

	return ret;
}

static void spapr_tce_init_table_group(struct pci_dev *pdev,
				       struct device_node *pdn,
				       struct dynamic_dma_window_prop prop)
{
	struct iommu_table_group  *table_group = PCI_DN(pdn)->table_group;
	u32 ddw_avail[DDW_APPLICABLE_SIZE];

	struct ddw_query_response query;
	int ret;

	/* Only for normal boot with default window. Doesn't matter during
	 * kdump, since these will not be used during kdump.
	 */
	if (is_kdump_kernel())
		return;

	if (table_group->max_dynamic_windows_supported != 0)
		return; /* already initialized */

	table_group->tce32_start = be64_to_cpu(prop.dma_base);
	table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);

	if (!of_find_property(pdn, "ibm,dma-window", NULL))
		dev_err(&pdev->dev, "default dma window missing!\n");

	ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable",
			&ddw_avail[0], DDW_APPLICABLE_SIZE);
	if (ret) {
		table_group->max_dynamic_windows_supported = -1;
		return;
	}

	ret = query_ddw(pdev, ddw_avail, &query, pdn);
	if (ret) {
		dev_err(&pdev->dev, "%s: query_ddw failed\n", __func__);
		table_group->max_dynamic_windows_supported = -1;
		return;
	}

	if (query.windows_available == 0)
		table_group->max_dynamic_windows_supported = 1;
	else
		table_group->max_dynamic_windows_supported = IOMMU_TABLE_GROUP_MAX_TABLES;

	table_group->max_levels = 1;
	table_group->pgsizes |= query_page_size_to_mask(query.page_size);
}

static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
	struct device_node *pdn, *dn;
@@ -1697,13 +1755,6 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
				be32_to_cpu(prop.tce_shift), NULL,
				&iommu_table_lpar_multi_ops);

		/* Only for normal boot with default window. Doesn't matter even
		 * if we set these with DDW which is 64bit during kdump, since
		 * these will not be used during kdump.
		 */
		pci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
		pci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);

		iommu_init_table(tbl, pci->phb->node, 0, 0);
		iommu_register_group(pci->table_group,
				pci_domain_nr(pci->phb->bus), 0);
@@ -1712,6 +1763,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
		pr_debug("  found DMA window, table: %p\n", pci->table_group);
	}

	spapr_tce_init_table_group(dev, pdn, prop);

	set_iommu_table_base(&dev->dev, pci->table_group->tables[0]);
	iommu_add_device(pci->table_group, &dev->dev);
}