diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index c34aa47b9833f..f2549b1fb12a5 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -354,6 +354,8 @@ struct apple_dart { u32 pgsize; u32 num_streams; u32 supports_bypass : 1; + /* J613 MTP keeps issuing DMA in the boot loader identity domain. */ + bool live_mtp; u32 four_level : 1; u32 locked : 1; u32 tunneled : 1; @@ -3087,6 +3089,10 @@ static int apple_dart_attach_dev_paging(struct iommu_domain *domain, struct apple_dart_domain *dart_domain = to_dart_domain(domain); bool streams_added = false; + for_each_stream_map(i, cfg, stream_map) + if (stream_map->dart->live_mtp) + return -EBUSY; + for_each_stream_map(i, cfg, stream_map) WARN_ON(pm_runtime_get_sync(stream_map->dart->dev) < 0); @@ -3180,6 +3186,10 @@ static int apple_dart_attach_dev_blocked(struct iommu_domain *domain, struct apple_dart_stream_map *stream_map; int i; + for_each_stream_map(i, cfg, stream_map) + if (stream_map->dart->live_mtp) + return -EBUSY; + if (cfg->locked) return -EINVAL; @@ -3918,7 +3928,8 @@ static int apple_dart_def_domain_type(struct device *dev) if (cfg->stream_maps[0].dart->managed_sids || apple_dart_has_borrowed(cfg->stream_maps[0].dart)) return IOMMU_DOMAIN_DMA; - if (cfg->stream_maps[0].dart->retained_mtp) + if (cfg->stream_maps[0].dart->retained_mtp || + cfg->stream_maps[0].dart->live_mtp) return IOMMU_DOMAIN_IDENTITY; if (cfg->stream_maps[0].dart->pgsize > PAGE_SIZE) return IOMMU_DOMAIN_IDENTITY; @@ -5095,6 +5106,29 @@ static int apple_dart_probe(struct platform_device *pdev) goto err_clk_disable; } + /* A live MTP epoch must never lose its firmware DMA addresses. */ + if (of_property_present(dev->of_node, "apple,bypass-handoff-streams")) { + u32 stream; + + /* A zero stream value advertises no live handoff (e.g. J700). */ + if (of_property_count_u32_elems(dev->of_node, + "apple,bypass-handoff-streams") != 1 || + of_property_read_u32(dev->of_node, "apple,bypass-handoff-streams", + &stream)) { + ret = -EINVAL; + goto err_clk_disable; + } + if (stream && (!of_machine_is_compatible("apple,j613") || + !of_device_is_compatible(dev->of_node, "apple,t8122-dart") || + res->start != 0x2fa808000ULL || !dart->supports_bypass || + stream != 1 || stream >= dart->num_streams || + apple_dart_readl(dart, DART_TCR(dart, stream)) != dart->hw->tcr_bypass)) { + ret = -EINVAL; + goto err_clk_disable; + } + dart->live_mtp = stream != 0; + } + ret = apple_dart_read_remaps(dart); if (ret) goto err_clk_disable; @@ -5233,7 +5267,7 @@ static int apple_dart_probe(struct platform_device *pdev) } /* ENABLE is write-one-to-set; no foreign stream changes state. */ apple_dart_writel(dart, dart->managed_sids, dart->hw->enable_streams); - } else if (!dart->locked && !dart->retained_mtp && !dart->preserve_display) { + } else if (!dart->locked && !dart->retained_mtp && !dart->live_mtp && !dart->preserve_display) { ret = apple_dart_hw_reset(dart); if (ret) goto err_clk_disable; @@ -5469,7 +5503,7 @@ static void apple_dart_remove(struct platform_device *pdev) * A command issued then never completes. The next probe resets the * block after that clock is running again. */ - if (!dart->locked && !dart->retained_mtp && + if (!dart->locked && !dart->retained_mtp && !dart->live_mtp && !READ_ONCE(dart->commands_gated)) apple_dart_hw_reset(dart); @@ -5479,7 +5513,8 @@ static void apple_dart_remove(struct platform_device *pdev) iommu_device_unregister(&dart->iommu); iommu_device_sysfs_remove(&dart->iommu); - clk_bulk_disable_unprepare(dart->num_clks, dart->clks); + if (!dart->live_mtp) + clk_bulk_disable_unprepare(dart->num_clks, dart->clks); } static void apple_dart_shutdown(struct platform_device *pdev) @@ -5623,6 +5658,14 @@ static __maybe_unused int apple_dart_suspend(struct device *dev) { struct apple_dart *dart = dev_get_drvdata(dev); + /* + * The adopted MTP keeps issuing DMA through its firmware bypass. + * Like its RTKit helper, admit only suspend-to-idle: leave the DART + * untouched while that live session and its power domain stay on. + */ + if (dart->live_mtp) + return pm_suspend_target_state == PM_SUSPEND_TO_IDLE ? 0 : -EBUSY; + dart->tunnel_state_restored = false; if (READ_ONCE(dart->commands_gated)) return 0; @@ -5759,7 +5802,7 @@ static __maybe_unused int apple_dart_resume(struct device *dev) int ret; /* No reset or restore: see apple_dart_suspend(). */ - if (dart->cold_ane) + if (dart->cold_ane || dart->live_mtp) return 0; /* Powered down by its DCP, which restores it at power-up. */ if (READ_ONCE(dart->host_off)) diff --git a/drivers/soc/apple/rtkit-helper.c b/drivers/soc/apple/rtkit-helper.c index 07b5840da8fde..df2f5334ac6b6 100644 --- a/drivers/soc/apple/rtkit-helper.c +++ b/drivers/soc/apple/rtkit-helper.c @@ -406,6 +406,8 @@ static const struct dev_pm_ops apple_rtkit_helper_pm_ops = { static const struct of_device_id apple_rtkit_helper_of_match[] = { { .compatible = "apple,rtk-helper-asc4" }, + /* J613/J615 25G83 DTs omit the generic fallback (see t8122-j613-25g83.dts). */ + { .compatible = "apple,t8122-rtk-helper-asc4" }, {}, }; MODULE_DEVICE_TABLE(of, apple_rtkit_helper_of_match);