summaryrefslogtreecommitdiff
path: root/drivers/interconnect/bulk.c
blob: 8b1d8a412464aa10add1e91dabe6bf930874ba99 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: GPL-2.0

#include <linux/interconnect-provider.h>
#include <linux/device.h>
#include <linux/export.h>

/**
 * of_icc_bulk_get() - get interconnect paths
 * @dev: the device requesting the path
 * @num_paths: the number of icc_bulk_data
 * @paths: the table with the paths we want to get
 *
 * Returns 0 on success or negative errno otherwise.
 */
int __must_check of_icc_bulk_get(struct device *dev, int num_paths,
				 struct icc_bulk_data *paths)
{
	int ret, i;

	for (i = 0; i < num_paths; i++) {
		paths[i].path = of_icc_get(dev, paths[i].name);
		if (IS_ERR(paths[i].path)) {
			ret = PTR_ERR(paths[i].path);
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "of_icc_get() failed on path %s (%d)\n",
					paths[i].name, ret);
			paths[i].path = NULL;
			goto err;
		}
	}

	return 0;

err:
	icc_bulk_put(i, paths);

	return ret;
}
EXPORT_SYMBOL_GPL(of_icc_bulk_get);

/**
 * icc_bulk_put() - put a list of interconnect paths
 * @num_paths: the number of icc_bulk_data
 * @paths: the icc_bulk_data table with the paths being put
 */
void icc_bulk_put(int num_paths, struct icc_bulk_data *paths)
{
	while (--num_paths >= 0) {
		icc_put(paths[num_paths].path);
		paths[num_paths].path = NULL;
	}
}
EXPORT_SYMBOL_GPL(icc_bulk_put);

/**
 * icc_bulk_set_bw() - set bandwidth to a set of paths
 * @num_paths: the number of icc_bulk_data
 * @paths: the icc_bulk_data table containing the paths and bandwidth
 *
 * Returns 0 on success or negative errno otherwise.
 */
int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths)
{
	int ret = 0;
	int i;

	for (i = 0; i < num_paths; i++) {
		ret = icc_set_bw(paths[i].path, paths[i].avg_bw, paths[i].peak_bw);
		if (ret) {
			pr_err("icc_set_bw() failed on path %s (%d)\n", paths[i].name, ret);
			return ret;
		}
	}

	return ret;
}
EXPORT_SYMBOL_GPL(icc_bulk_set_bw);

/**
 * icc_bulk_enable() - enable a previously disabled set of paths
 * @num_paths: the number of icc_bulk_data
 * @paths: the icc_bulk_data table containing the paths and bandwidth
 *
 * Returns 0 on success or negative errno otherwise.
 */
int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths)
{
	int ret, i;

	for (i = 0; i < num_paths; i++) {
		ret = icc_enable(paths[i].path);
		if (ret) {
			pr_err("icc_enable() failed on path %s (%d)\n", paths[i].name, ret);
			goto err;
		}
	}

	return 0;

err:
	icc_bulk_disable(i, paths);

	return ret;
}
EXPORT_SYMBOL_GPL(icc_bulk_enable);

/**
 * icc_bulk_disable() - disable a set of interconnect paths
 * @num_paths: the number of icc_bulk_data
 * @paths: the icc_bulk_data table containing the paths and bandwidth
 */
void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths)
{
	while (--num_paths >= 0)
		icc_disable(paths[num_paths].path);
}
EXPORT_SYMBOL_GPL(icc_bulk_disable);

struct icc_bulk_devres {
	struct icc_bulk_data *paths;
	int num_paths;
};

static void devm_icc_bulk_release(struct device *dev, void *res)
{
	struct icc_bulk_devres *devres = res;

	icc_bulk_put(devres->num_paths, devres->paths);
}

/**
 * devm_of_icc_bulk_get() - resource managed of_icc_bulk_get
 * @dev: the device requesting the path
 * @num_paths: the number of icc_bulk_data
 * @paths: the table with the paths we want to get
 *
 * Returns 0 on success or negative errno otherwise.
 */
int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths)
{
	struct icc_bulk_devres *devres;
	int ret;

	devres = devres_alloc(devm_icc_bulk_release, sizeof(*devres), GFP_KERNEL);
	if (!devres)
		return -ENOMEM;

	ret = of_icc_bulk_get(dev, num_paths, paths);
	if (!ret) {
		devres->paths = paths;
		devres->num_paths = num_paths;
		devres_add(dev, devres);
	} else {
		devres_free(devres);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(devm_of_icc_bulk_get);