Skip to content

Commit 483e0bd

Browse files
nicolincwilldeacon
authored andcommitted
iommu/tegra241-cmdqv: Do not allocate vcmdq until dma_set_mask_and_coherent
It's observed that, when the first 4GB of system memory was reserved, all VCMDQ allocations failed (even with the smallest qsz in the last attempt): arm-smmu-v3: found companion CMDQV device: NVDA200C:00 arm-smmu-v3: option mask 0x10 arm-smmu-v3: failed to allocate queue (0x8000 bytes) for vcmdq0 acpi NVDA200C:00: tegra241_cmdqv: Falling back to standard SMMU CMDQ arm-smmu-v3: ias 48-bit, oas 48-bit (features 0x001e1fbf) arm-smmu-v3: allocated 524288 entries for cmdq arm-smmu-v3: allocated 524288 entries for evtq arm-smmu-v3: allocated 524288 entries for priq This is because the 4GB reserved memory shifted the entire DMA zone from a lower 32-bit range (on a system without the 4GB carveout) to higher range, while the dev->coherent_dma_mask was set to DMA_BIT_MASK(32) by default. The dma_set_mask_and_coherent() call is done in arm_smmu_device_hw_probe() of the SMMU driver. So any DMA allocation from tegra241_cmdqv_probe() must wait until the coherent_dma_mask is correctly set. Move the vintf/vcmdq structure initialization routine into a different op, "init_structures". Call it at the end of arm_smmu_init_structures(), where standard SMMU queues get allocated. Most of the impl_ops aren't ready until vintf/vcmdq structure are init-ed. So replace the full impl_ops with an init_ops in __tegra241_cmdqv_probe(). And switch to tegra241_cmdqv_impl_ops later in arm_smmu_init_structures(). Note that tegra241_cmdqv_impl_ops does not link to the new init_structures op after this switch, since there is no point in having it once it's done. Fixes: 918eb5c ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV") Reported-by: Matt Ochs <[email protected]> Signed-off-by: Nicolin Chen <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/530993c3aafa1b0fc3d879b8119e13c629d12e2b.1725503154.git.nicolinc@nvidia.com Signed-off-by: Will Deacon <[email protected]>
1 parent 2408b81 commit 483e0bd

File tree

3 files changed

+60
-33
lines changed

3 files changed

+60
-33
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3744,7 +3744,14 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
37443744
if (ret)
37453745
return ret;
37463746

3747-
return arm_smmu_init_strtab(smmu);
3747+
ret = arm_smmu_init_strtab(smmu);
3748+
if (ret)
3749+
return ret;
3750+
3751+
if (smmu->impl_ops && smmu->impl_ops->init_structures)
3752+
return smmu->impl_ops->init_structures(smmu);
3753+
3754+
return 0;
37483755
}
37493756

37503757
static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ struct arm_smmu_strtab_cfg {
643643
struct arm_smmu_impl_ops {
644644
int (*device_reset)(struct arm_smmu_device *smmu);
645645
void (*device_remove)(struct arm_smmu_device *smmu);
646+
int (*init_structures)(struct arm_smmu_device *smmu);
646647
struct arm_smmu_cmdq *(*get_secondary_cmdq)(
647648
struct arm_smmu_device *smmu, struct arm_smmu_cmdq_ent *ent);
648649
};

drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -755,18 +755,65 @@ tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
755755
return res;
756756
}
757757

758+
static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
759+
{
760+
struct tegra241_cmdqv *cmdqv =
761+
container_of(smmu, struct tegra241_cmdqv, smmu);
762+
struct tegra241_vintf *vintf;
763+
int lidx;
764+
int ret;
765+
766+
vintf = kzalloc(sizeof(*vintf), GFP_KERNEL);
767+
if (!vintf)
768+
goto out_fallback;
769+
770+
/* Init VINTF0 for in-kernel use */
771+
ret = tegra241_cmdqv_init_vintf(cmdqv, 0, vintf);
772+
if (ret) {
773+
dev_err(cmdqv->dev, "failed to init vintf0: %d\n", ret);
774+
goto free_vintf;
775+
}
776+
777+
/* Preallocate logical VCMDQs to VINTF0 */
778+
for (lidx = 0; lidx < cmdqv->num_lvcmdqs_per_vintf; lidx++) {
779+
struct tegra241_vcmdq *vcmdq;
780+
781+
vcmdq = tegra241_vintf_alloc_lvcmdq(vintf, lidx);
782+
if (IS_ERR(vcmdq))
783+
goto free_lvcmdq;
784+
}
785+
786+
/* Now, we are ready to run all the impl ops */
787+
smmu->impl_ops = &tegra241_cmdqv_impl_ops;
788+
return 0;
789+
790+
free_lvcmdq:
791+
for (lidx--; lidx >= 0; lidx--)
792+
tegra241_vintf_free_lvcmdq(vintf, lidx);
793+
tegra241_cmdqv_deinit_vintf(cmdqv, vintf->idx);
794+
free_vintf:
795+
kfree(vintf);
796+
out_fallback:
797+
dev_info(smmu->impl_dev, "Falling back to standard SMMU CMDQ\n");
798+
smmu->options &= ~ARM_SMMU_OPT_TEGRA241_CMDQV;
799+
tegra241_cmdqv_remove(smmu);
800+
return 0;
801+
}
802+
758803
struct dentry *cmdqv_debugfs_dir;
759804

760805
static struct arm_smmu_device *
761806
__tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
762807
int irq)
763808
{
809+
static const struct arm_smmu_impl_ops init_ops = {
810+
.init_structures = tegra241_cmdqv_init_structures,
811+
.device_remove = tegra241_cmdqv_remove,
812+
};
764813
struct tegra241_cmdqv *cmdqv = NULL;
765814
struct arm_smmu_device *new_smmu;
766-
struct tegra241_vintf *vintf;
767815
void __iomem *base;
768816
u32 regval;
769-
int lidx;
770817
int ret;
771818

772819
static_assert(offsetof(struct tegra241_cmdqv, smmu) == 0);
@@ -815,26 +862,6 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
815862

816863
ida_init(&cmdqv->vintf_ids);
817864

818-
vintf = kzalloc(sizeof(*vintf), GFP_KERNEL);
819-
if (!vintf)
820-
goto destroy_ids;
821-
822-
/* Init VINTF0 for in-kernel use */
823-
ret = tegra241_cmdqv_init_vintf(cmdqv, 0, vintf);
824-
if (ret) {
825-
dev_err(cmdqv->dev, "failed to init vintf0: %d\n", ret);
826-
goto free_vintf;
827-
}
828-
829-
/* Preallocate logical VCMDQs to VINTF0 */
830-
for (lidx = 0; lidx < cmdqv->num_lvcmdqs_per_vintf; lidx++) {
831-
struct tegra241_vcmdq *vcmdq;
832-
833-
vcmdq = tegra241_vintf_alloc_lvcmdq(vintf, lidx);
834-
if (IS_ERR(vcmdq))
835-
goto free_lvcmdq;
836-
}
837-
838865
#ifdef CONFIG_IOMMU_DEBUGFS
839866
if (!cmdqv_debugfs_dir) {
840867
cmdqv_debugfs_dir =
@@ -844,19 +871,11 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
844871
}
845872
#endif
846873

847-
new_smmu->impl_ops = &tegra241_cmdqv_impl_ops;
874+
/* Provide init-level ops only, until tegra241_cmdqv_init_structures */
875+
new_smmu->impl_ops = &init_ops;
848876

849877
return new_smmu;
850878

851-
free_lvcmdq:
852-
for (lidx--; lidx >= 0; lidx--)
853-
tegra241_vintf_free_lvcmdq(vintf, lidx);
854-
tegra241_cmdqv_deinit_vintf(cmdqv, vintf->idx);
855-
free_vintf:
856-
kfree(vintf);
857-
destroy_ids:
858-
ida_destroy(&cmdqv->vintf_ids);
859-
kfree(cmdqv->vintfs);
860879
free_irq:
861880
if (cmdqv->irq > 0)
862881
free_irq(cmdqv->irq, cmdqv);

0 commit comments

Comments
 (0)