Commit 57fb481f authored by Yong Wu's avatar Yong Wu Committed by Joerg Roedel
Browse files

iommu/mediatek: Get the proper bankid for multi banks



We preassign some ports in a special bank via the new defined
banks_portmsk. Put it in the plat_data means it is not expected to be
adjusted dynamically.

If the iommu id in the iommu consumer's dtsi node is inside this
banks_portmsk, then we switch it to this special iommu bank, and
initialise the IOMMU bank HW.

Each bank has the independent pgtable(4GB iova range). Each bank
is a independent iommu domain/group. Currently we don't separate different
iova ranges inside a bank.

Signed-off-by: default avatarYong Wu <yong.wu@mediatek.com>
Reviewed-by: default avatarAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: default avatarMatthias Brugger <matthias.bgg@gmail.com>
Link: https://lore.kernel.org/r/20220503071427.2285-33-yong.wu@mediatek.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent d72e0ff5
Loading
Loading
Loading
Loading
+48 −7
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ struct mtk_iommu_plat_data {

	u8                  banks_num;
	bool                banks_enable[MTK_IOMMU_BANK_MAX];
	unsigned int        banks_portmsk[MTK_IOMMU_BANK_MAX];
	unsigned char       larbid_remap[MTK_LARB_COM_MAX][MTK_LARB_SUBCOM_MAX];
};

@@ -467,6 +468,30 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
	return IRQ_HANDLED;
}

static unsigned int mtk_iommu_get_bank_id(struct device *dev,
					  const struct mtk_iommu_plat_data *plat_data)
{
	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
	unsigned int i, portmsk = 0, bankid = 0;

	if (plat_data->banks_num == 1)
		return bankid;

	for (i = 0; i < fwspec->num_ids; i++)
		portmsk |= BIT(MTK_M4U_TO_PORT(fwspec->ids[i]));

	for (i = 0; i < plat_data->banks_num && i < MTK_IOMMU_BANK_MAX; i++) {
		if (!plat_data->banks_enable[i])
			continue;

		if (portmsk & plat_data->banks_portmsk[i]) {
			bankid = i;
			break;
		}
	}
	return bankid; /* default is 0 */
}

static int mtk_iommu_get_iova_region_id(struct device *dev,
					const struct mtk_iommu_plat_data *plat_data)
{
@@ -619,13 +644,14 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
	struct list_head *hw_list = data->hw_list;
	struct device *m4udev = data->dev;
	struct mtk_iommu_bank_data *bank;
	unsigned int bankid = 0;
	unsigned int bankid;
	int ret, region_id;

	region_id = mtk_iommu_get_iova_region_id(dev, data->plat_data);
	if (region_id < 0)
		return region_id;

	bankid = mtk_iommu_get_bank_id(dev, data->plat_data);
	mutex_lock(&dom->mutex);
	if (!dom->bank) {
		/* Data is in the frstdata in sharing pgtable case. */
@@ -797,27 +823,42 @@ static void mtk_iommu_release_device(struct device *dev)
	iommu_fwspec_free(dev);
}

static int mtk_iommu_get_group_id(struct device *dev, const struct mtk_iommu_plat_data *plat_data)
{
	unsigned int bankid;

	/*
	 * If the bank function is enabled, each bank is a iommu group/domain.
	 * Otherwise, each iova region is a iommu group/domain.
	 */
	bankid = mtk_iommu_get_bank_id(dev, plat_data);
	if (bankid)
		return bankid;

	return mtk_iommu_get_iova_region_id(dev, plat_data);
}

static struct iommu_group *mtk_iommu_device_group(struct device *dev)
{
	struct mtk_iommu_data *c_data = dev_iommu_priv_get(dev), *data;
	struct list_head *hw_list = c_data->hw_list;
	struct iommu_group *group;
	int regionid;
	int groupid;

	data = mtk_iommu_get_frst_data(hw_list);
	if (!data)
		return ERR_PTR(-ENODEV);

	regionid = mtk_iommu_get_iova_region_id(dev, data->plat_data);
	if (regionid < 0)
		return ERR_PTR(regionid);
	groupid = mtk_iommu_get_group_id(dev, data->plat_data);
	if (groupid < 0)
		return ERR_PTR(groupid);

	mutex_lock(&data->mutex);
	group = data->m4u_group[regionid];
	group = data->m4u_group[groupid];
	if (!group) {
		group = iommu_group_alloc();
		if (!IS_ERR(group))
			data->m4u_group[regionid] = group;
			data->m4u_group[groupid] = group;
	} else {
		iommu_group_ref_get(group);
	}