1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <linux/interconnect-provider.h> |
4 | #include <linux/device.h> |
5 | #include <linux/export.h> |
6 | |
7 | /** |
8 | * of_icc_bulk_get() - get interconnect paths |
9 | * @dev: the device requesting the path |
10 | * @num_paths: the number of icc_bulk_data |
11 | * @paths: the table with the paths we want to get |
12 | * |
13 | * Returns 0 on success or negative errno otherwise. |
14 | */ |
15 | int __must_check of_icc_bulk_get(struct device *dev, int num_paths, |
16 | struct icc_bulk_data *paths) |
17 | { |
18 | int ret, i; |
19 | |
20 | for (i = 0; i < num_paths; i++) { |
21 | paths[i].path = of_icc_get(dev, name: paths[i].name); |
22 | if (IS_ERR(ptr: paths[i].path)) { |
23 | ret = PTR_ERR(ptr: paths[i].path); |
24 | if (ret != -EPROBE_DEFER) |
25 | dev_err(dev, "of_icc_get() failed on path %s (%d)\n" , |
26 | paths[i].name, ret); |
27 | paths[i].path = NULL; |
28 | goto err; |
29 | } |
30 | } |
31 | |
32 | return 0; |
33 | |
34 | err: |
35 | icc_bulk_put(num_paths: i, paths); |
36 | |
37 | return ret; |
38 | } |
39 | EXPORT_SYMBOL_GPL(of_icc_bulk_get); |
40 | |
41 | /** |
42 | * icc_bulk_put() - put a list of interconnect paths |
43 | * @num_paths: the number of icc_bulk_data |
44 | * @paths: the icc_bulk_data table with the paths being put |
45 | */ |
46 | void icc_bulk_put(int num_paths, struct icc_bulk_data *paths) |
47 | { |
48 | while (--num_paths >= 0) { |
49 | icc_put(path: paths[num_paths].path); |
50 | paths[num_paths].path = NULL; |
51 | } |
52 | } |
53 | EXPORT_SYMBOL_GPL(icc_bulk_put); |
54 | |
55 | /** |
56 | * icc_bulk_set_bw() - set bandwidth to a set of paths |
57 | * @num_paths: the number of icc_bulk_data |
58 | * @paths: the icc_bulk_data table containing the paths and bandwidth |
59 | * |
60 | * Returns 0 on success or negative errno otherwise. |
61 | */ |
62 | int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths) |
63 | { |
64 | int ret = 0; |
65 | int i; |
66 | |
67 | for (i = 0; i < num_paths; i++) { |
68 | ret = icc_set_bw(path: paths[i].path, avg_bw: paths[i].avg_bw, peak_bw: paths[i].peak_bw); |
69 | if (ret) { |
70 | pr_err("icc_set_bw() failed on path %s (%d)\n" , paths[i].name, ret); |
71 | return ret; |
72 | } |
73 | } |
74 | |
75 | return ret; |
76 | } |
77 | EXPORT_SYMBOL_GPL(icc_bulk_set_bw); |
78 | |
79 | /** |
80 | * icc_bulk_enable() - enable a previously disabled set of paths |
81 | * @num_paths: the number of icc_bulk_data |
82 | * @paths: the icc_bulk_data table containing the paths and bandwidth |
83 | * |
84 | * Returns 0 on success or negative errno otherwise. |
85 | */ |
86 | int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths) |
87 | { |
88 | int ret, i; |
89 | |
90 | for (i = 0; i < num_paths; i++) { |
91 | ret = icc_enable(path: paths[i].path); |
92 | if (ret) { |
93 | pr_err("icc_enable() failed on path %s (%d)\n" , paths[i].name, ret); |
94 | goto err; |
95 | } |
96 | } |
97 | |
98 | return 0; |
99 | |
100 | err: |
101 | icc_bulk_disable(num_paths: i, paths); |
102 | |
103 | return ret; |
104 | } |
105 | EXPORT_SYMBOL_GPL(icc_bulk_enable); |
106 | |
107 | /** |
108 | * icc_bulk_disable() - disable a set of interconnect paths |
109 | * @num_paths: the number of icc_bulk_data |
110 | * @paths: the icc_bulk_data table containing the paths and bandwidth |
111 | */ |
112 | void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths) |
113 | { |
114 | while (--num_paths >= 0) |
115 | icc_disable(path: paths[num_paths].path); |
116 | } |
117 | EXPORT_SYMBOL_GPL(icc_bulk_disable); |
118 | |
119 | struct icc_bulk_devres { |
120 | struct icc_bulk_data *paths; |
121 | int num_paths; |
122 | }; |
123 | |
124 | static void devm_icc_bulk_release(struct device *dev, void *res) |
125 | { |
126 | struct icc_bulk_devres *devres = res; |
127 | |
128 | icc_bulk_put(devres->num_paths, devres->paths); |
129 | } |
130 | |
131 | /** |
132 | * devm_of_icc_bulk_get() - resource managed of_icc_bulk_get |
133 | * @dev: the device requesting the path |
134 | * @num_paths: the number of icc_bulk_data |
135 | * @paths: the table with the paths we want to get |
136 | * |
137 | * Returns 0 on success or negative errno otherwise. |
138 | */ |
139 | int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths) |
140 | { |
141 | struct icc_bulk_devres *devres; |
142 | int ret; |
143 | |
144 | devres = devres_alloc(devm_icc_bulk_release, sizeof(*devres), GFP_KERNEL); |
145 | if (!devres) |
146 | return -ENOMEM; |
147 | |
148 | ret = of_icc_bulk_get(dev, num_paths, paths); |
149 | if (!ret) { |
150 | devres->paths = paths; |
151 | devres->num_paths = num_paths; |
152 | devres_add(dev, res: devres); |
153 | } else { |
154 | devres_free(res: devres); |
155 | } |
156 | |
157 | return ret; |
158 | } |
159 | EXPORT_SYMBOL_GPL(devm_of_icc_bulk_get); |
160 | |