Skip to content

Commit 0f181d3

Browse files
JeffyCNjoergroedel
authored andcommitted
iommu/rockchip: Add runtime PM support
When the power domain is powered off, the IOMMU cannot be accessed and register programming must be deferred until the power domain becomes enabled. Add runtime PM support, and use runtime PM device link from IOMMU to master to enable and disable IOMMU. Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 4d88a8a commit 0f181d3

File tree

1 file changed

+129
-52
lines changed

1 file changed

+129
-52
lines changed

drivers/iommu/rockchip-iommu.c

Lines changed: 129 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/of_iommu.h>
2323
#include <linux/of_platform.h>
2424
#include <linux/platform_device.h>
25+
#include <linux/pm_runtime.h>
2526
#include <linux/slab.h>
2627
#include <linux/spinlock.h>
2728

@@ -106,6 +107,7 @@ struct rk_iommu {
106107
};
107108

108109
struct rk_iommudata {
110+
struct device_link *link; /* runtime PM link from IOMMU to master */
109111
struct rk_iommu *iommu;
110112
};
111113

@@ -520,7 +522,11 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
520522
irqreturn_t ret = IRQ_NONE;
521523
int i;
522524

523-
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
525+
if (WARN_ON(!pm_runtime_get_if_in_use(iommu->dev)))
526+
return 0;
527+
528+
if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
529+
goto out;
524530

525531
for (i = 0; i < iommu->num_mmu; i++) {
526532
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
@@ -570,6 +576,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
570576

571577
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
572578

579+
out:
580+
pm_runtime_put(iommu->dev);
573581
return ret;
574582
}
575583

@@ -611,10 +619,17 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
611619
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
612620
list_for_each(pos, &rk_domain->iommus) {
613621
struct rk_iommu *iommu;
622+
614623
iommu = list_entry(pos, struct rk_iommu, node);
615-
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
616-
rk_iommu_zap_lines(iommu, iova, size);
617-
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
624+
625+
/* Only zap TLBs of IOMMUs that are powered on. */
626+
if (pm_runtime_get_if_in_use(iommu->dev)) {
627+
WARN_ON(clk_bulk_enable(iommu->num_clocks,
628+
iommu->clocks));
629+
rk_iommu_zap_lines(iommu, iova, size);
630+
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
631+
pm_runtime_put(iommu->dev);
632+
}
618633
}
619634
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
620635
}
@@ -817,22 +832,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
817832
return data ? data->iommu : NULL;
818833
}
819834

820-
static int rk_iommu_attach_device(struct iommu_domain *domain,
821-
struct device *dev)
835+
/* Must be called with iommu powered on and attached */
836+
static void rk_iommu_disable(struct rk_iommu *iommu)
822837
{
823-
struct rk_iommu *iommu;
838+
int i;
839+
840+
/* Ignore error while disabling, just keep going */
841+
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
842+
rk_iommu_enable_stall(iommu);
843+
rk_iommu_disable_paging(iommu);
844+
for (i = 0; i < iommu->num_mmu; i++) {
845+
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
846+
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
847+
}
848+
rk_iommu_disable_stall(iommu);
849+
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
850+
}
851+
852+
/* Must be called with iommu powered on and attached */
853+
static int rk_iommu_enable(struct rk_iommu *iommu)
854+
{
855+
struct iommu_domain *domain = iommu->domain;
824856
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
825-
unsigned long flags;
826857
int ret, i;
827858

828-
/*
829-
* Allow 'virtual devices' (e.g., drm) to attach to domain.
830-
* Such a device does not belong to an iommu group.
831-
*/
832-
iommu = rk_iommu_from_dev(dev);
833-
if (!iommu)
834-
return 0;
835-
836859
ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
837860
if (ret)
838861
return ret;
@@ -845,8 +868,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
845868
if (ret)
846869
goto out_disable_stall;
847870

848-
iommu->domain = domain;
849-
850871
for (i = 0; i < iommu->num_mmu; i++) {
851872
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
852873
rk_domain->dt_dma);
@@ -855,14 +876,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
855876
}
856877

857878
ret = rk_iommu_enable_paging(iommu);
858-
if (ret)
859-
goto out_disable_stall;
860-
861-
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
862-
list_add_tail(&iommu->node, &rk_domain->iommus);
863-
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
864-
865-
dev_dbg(dev, "Attached to iommu domain\n");
866879

867880
out_disable_stall:
868881
rk_iommu_disable_stall(iommu);
@@ -877,31 +890,71 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
877890
struct rk_iommu *iommu;
878891
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
879892
unsigned long flags;
880-
int i;
881893

882894
/* Allow 'virtual devices' (eg drm) to detach from domain */
883895
iommu = rk_iommu_from_dev(dev);
884896
if (!iommu)
885897
return;
886898

899+
dev_dbg(dev, "Detaching from iommu domain\n");
900+
901+
/* iommu already detached */
902+
if (iommu->domain != domain)
903+
return;
904+
905+
iommu->domain = NULL;
906+
887907
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
888908
list_del_init(&iommu->node);
889909
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
890910

891-
/* Ignore error while disabling, just keep going */
892-
WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks));
893-
rk_iommu_enable_stall(iommu);
894-
rk_iommu_disable_paging(iommu);
895-
for (i = 0; i < iommu->num_mmu; i++) {
896-
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0);
897-
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0);
911+
if (pm_runtime_get_if_in_use(iommu->dev)) {
912+
rk_iommu_disable(iommu);
913+
pm_runtime_put(iommu->dev);
898914
}
899-
rk_iommu_disable_stall(iommu);
900-
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
915+
}
901916

902-
iommu->domain = NULL;
917+
static int rk_iommu_attach_device(struct iommu_domain *domain,
918+
struct device *dev)
919+
{
920+
struct rk_iommu *iommu;
921+
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
922+
unsigned long flags;
923+
int ret;
903924

904-
dev_dbg(dev, "Detached from iommu domain\n");
925+
/*
926+
* Allow 'virtual devices' (e.g., drm) to attach to domain.
927+
* Such a device does not belong to an iommu group.
928+
*/
929+
iommu = rk_iommu_from_dev(dev);
930+
if (!iommu)
931+
return 0;
932+
933+
dev_dbg(dev, "Attaching to iommu domain\n");
934+
935+
/* iommu already attached */
936+
if (iommu->domain == domain)
937+
return 0;
938+
939+
if (iommu->domain)
940+
rk_iommu_detach_device(iommu->domain, dev);
941+
942+
iommu->domain = domain;
943+
944+
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
945+
list_add_tail(&iommu->node, &rk_domain->iommus);
946+
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
947+
948+
if (!pm_runtime_get_if_in_use(iommu->dev))
949+
return 0;
950+
951+
ret = rk_iommu_enable(iommu);
952+
if (ret)
953+
rk_iommu_detach_device(iommu->domain, dev);
954+
955+
pm_runtime_put(iommu->dev);
956+
957+
return ret;
905958
}
906959

907960
static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
@@ -989,27 +1042,33 @@ static int rk_iommu_add_device(struct device *dev)
9891042
{
9901043
struct iommu_group *group;
9911044
struct rk_iommu *iommu;
1045+
struct rk_iommudata *data;
9921046

993-
iommu = rk_iommu_from_dev(dev);
994-
if (!iommu)
1047+
data = dev->archdata.iommu;
1048+
if (!data)
9951049
return -ENODEV;
9961050

1051+
iommu = rk_iommu_from_dev(dev);
1052+
9971053
group = iommu_group_get_for_dev(dev);
9981054
if (IS_ERR(group))
9991055
return PTR_ERR(group);
10001056
iommu_group_put(group);
10011057

10021058
iommu_device_link(&iommu->iommu, dev);
1059+
data->link = device_link_add(dev, iommu->dev, DL_FLAG_PM_RUNTIME);
10031060

10041061
return 0;
10051062
}
10061063

10071064
static void rk_iommu_remove_device(struct device *dev)
10081065
{
10091066
struct rk_iommu *iommu;
1067+
struct rk_iommudata *data = dev->archdata.iommu;
10101068

10111069
iommu = rk_iommu_from_dev(dev);
10121070

1071+
device_link_del(data->link);
10131072
iommu_device_unlink(&iommu->iommu, dev);
10141073
iommu_group_remove_device(dev);
10151074
}
@@ -1135,6 +1194,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
11351194

11361195
bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
11371196

1197+
pm_runtime_enable(dev);
1198+
11381199
return 0;
11391200
err_remove_sysfs:
11401201
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1145,21 +1206,36 @@ static int rk_iommu_probe(struct platform_device *pdev)
11451206

11461207
static void rk_iommu_shutdown(struct platform_device *pdev)
11471208
{
1148-
struct rk_iommu *iommu = platform_get_drvdata(pdev);
1209+
pm_runtime_force_suspend(&pdev->dev);
1210+
}
11491211

1150-
/*
1151-
* Be careful not to try to shutdown an otherwise unused
1152-
* IOMMU, as it is likely not to be clocked, and accessing it
1153-
* would just block. An IOMMU without a domain is likely to be
1154-
* unused, so let's use this as a (weak) guard.
1155-
*/
1156-
if (iommu && iommu->domain) {
1157-
rk_iommu_enable_stall(iommu);
1158-
rk_iommu_disable_paging(iommu);
1159-
rk_iommu_force_reset(iommu);
1160-
}
1212+
static int __maybe_unused rk_iommu_suspend(struct device *dev)
1213+
{
1214+
struct rk_iommu *iommu = dev_get_drvdata(dev);
1215+
1216+
if (!iommu->domain)
1217+
return 0;
1218+
1219+
rk_iommu_disable(iommu);
1220+
return 0;
1221+
}
1222+
1223+
static int __maybe_unused rk_iommu_resume(struct device *dev)
1224+
{
1225+
struct rk_iommu *iommu = dev_get_drvdata(dev);
1226+
1227+
if (!iommu->domain)
1228+
return 0;
1229+
1230+
return rk_iommu_enable(iommu);
11611231
}
11621232

1233+
static const struct dev_pm_ops rk_iommu_pm_ops = {
1234+
SET_RUNTIME_PM_OPS(rk_iommu_suspend, rk_iommu_resume, NULL)
1235+
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1236+
pm_runtime_force_resume)
1237+
};
1238+
11631239
static const struct of_device_id rk_iommu_dt_ids[] = {
11641240
{ .compatible = "rockchip,iommu" },
11651241
{ /* sentinel */ }
@@ -1172,6 +1248,7 @@ static struct platform_driver rk_iommu_driver = {
11721248
.driver = {
11731249
.name = "rk_iommu",
11741250
.of_match_table = rk_iommu_dt_ids,
1251+
.pm = &rk_iommu_pm_ops,
11751252
.suppress_bind_attrs = true,
11761253
},
11771254
};

0 commit comments

Comments
 (0)