From 9290fc3e8d0822b3c5ad721ddeb13a0c74f3d00b Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 14 Sep 2023 18:10:14 -0700 Subject: [PATCH] ANDROID: Flush deferred probe list before dropping host priv Some IOMMU devices might be deferred after the driver being loaded early, so we need to flush the deferred probe list, this will work if all dependencies already exist. Bug: 290582379 Change-Id: I5fb3af9b0f7d1b4dbf57078707112dfdb8a3dc23 Signed-off-by: Saravana Kannan Signed-off-by: Mostafa Saleh --- arch/arm64/kvm/pkvm.c | 10 ++++++---- drivers/base/dd.c | 23 +++++++++++++++++++++++ include/linux/device/driver.h | 1 + 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index b601ff98e9f2..789753790a28 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -504,10 +504,6 @@ static int __init finalize_pkvm(void) if (pkvm_load_early_modules()) pkvm_firmware_rmem_clear(); - /* If no DMA protection. */ - if (!pkvm_iommu_finalized()) - pkvm_firmware_rmem_clear(); - /* * Exclude HYP sections from kmemleak so that they don't get peeked * at, which would end badly once inaccessible. @@ -516,6 +512,12 @@ static int __init finalize_pkvm(void) kmemleak_free_part(__hyp_data_start, __hyp_data_end - __hyp_data_start); kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size); + flush_deferred_probe_now(); + + /* If no DMA protection. */ + if (!pkvm_iommu_finalized()) + pkvm_firmware_rmem_clear(); + ret = pkvm_drop_host_privileges(); if (ret) { pr_err("Failed to de-privilege the host kernel: %d\n", ret); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c463173f1fb1..1b7378843ceb 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -754,6 +754,29 @@ void wait_for_device_probe(void) } EXPORT_SYMBOL_GPL(wait_for_device_probe); +/** + * flush_deferred_probe_now + * + * This function should be used sparingly. It's meant for when we need to flush + * the deferred probe list at earlier initcall levels. Really meant only for KVM + * needs. This function should never be exported because it makes no sense for + * modules to call this. + */ +void flush_deferred_probe_now(void) +{ + /* + * Really shouldn't using this if deferred probe has already been + * enabled + */ + if (WARN_ON(driver_deferred_probe_enable)) + return; + + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + wait_for_device_probe(); + driver_deferred_probe_enable = false; +} + static int __driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index d2a71e25caab..b2d338904de2 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -134,6 +134,7 @@ extern struct device_driver *driver_find(const char *name, struct bus_type *bus); extern int driver_probe_done(void); extern void wait_for_device_probe(void); +extern void flush_deferred_probe_now(void); void __init wait_for_init_devices_probe(void); /* sysfs interface for exporting driver attributes */