Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accel/habanalabs/goya/goya_hwmgr.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
/*
4
* Copyright 2016-2022 HabanaLabs, Ltd.
5
* All Rights Reserved.
6
*/
7
8
#include "goyaP.h"
9
10
void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)
11
{
12
struct goya_device *goya = hdev->asic_specific;
13
14
if (!hdev->pdev)
15
return;
16
17
switch (freq) {
18
case PLL_HIGH:
19
hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);
20
hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);
21
hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);
22
break;
23
case PLL_LOW:
24
hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);
25
hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);
26
hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);
27
break;
28
case PLL_LAST:
29
hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);
30
hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);
31
hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);
32
break;
33
default:
34
dev_err(hdev->dev, "unknown frequency setting\n");
35
}
36
}
37
38
static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr,
39
char *buf)
40
{
41
struct hl_device *hdev = dev_get_drvdata(dev);
42
long value;
43
44
if (!hl_device_operational(hdev, NULL))
45
return -ENODEV;
46
47
value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, false);
48
49
if (value < 0)
50
return value;
51
52
return sprintf(buf, "%lu\n", value);
53
}
54
55
static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr,
56
const char *buf, size_t count)
57
{
58
struct hl_device *hdev = dev_get_drvdata(dev);
59
struct goya_device *goya = hdev->asic_specific;
60
int rc;
61
long value;
62
63
if (!hl_device_operational(hdev, NULL)) {
64
count = -ENODEV;
65
goto fail;
66
}
67
68
if (goya->pm_mng_profile == PM_AUTO) {
69
count = -EPERM;
70
goto fail;
71
}
72
73
rc = kstrtoul(buf, 0, &value);
74
75
if (rc) {
76
count = -EINVAL;
77
goto fail;
78
}
79
80
hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, value);
81
goya->mme_clk = value;
82
83
fail:
84
return count;
85
}
86
87
static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr,
88
char *buf)
89
{
90
struct hl_device *hdev = dev_get_drvdata(dev);
91
long value;
92
93
if (!hl_device_operational(hdev, NULL))
94
return -ENODEV;
95
96
value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
97
98
if (value < 0)
99
return value;
100
101
return sprintf(buf, "%lu\n", value);
102
}
103
104
static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr,
105
const char *buf, size_t count)
106
{
107
struct hl_device *hdev = dev_get_drvdata(dev);
108
struct goya_device *goya = hdev->asic_specific;
109
int rc;
110
long value;
111
112
if (!hl_device_operational(hdev, NULL)) {
113
count = -ENODEV;
114
goto fail;
115
}
116
117
if (goya->pm_mng_profile == PM_AUTO) {
118
count = -EPERM;
119
goto fail;
120
}
121
122
rc = kstrtoul(buf, 0, &value);
123
124
if (rc) {
125
count = -EINVAL;
126
goto fail;
127
}
128
129
hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
130
goya->tpc_clk = value;
131
132
fail:
133
return count;
134
}
135
136
static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr,
137
char *buf)
138
{
139
struct hl_device *hdev = dev_get_drvdata(dev);
140
long value;
141
142
if (!hl_device_operational(hdev, NULL))
143
return -ENODEV;
144
145
value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, false);
146
147
if (value < 0)
148
return value;
149
150
return sprintf(buf, "%lu\n", value);
151
}
152
153
static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr,
154
const char *buf, size_t count)
155
{
156
struct hl_device *hdev = dev_get_drvdata(dev);
157
struct goya_device *goya = hdev->asic_specific;
158
int rc;
159
long value;
160
161
if (!hl_device_operational(hdev, NULL)) {
162
count = -ENODEV;
163
goto fail;
164
}
165
166
if (goya->pm_mng_profile == PM_AUTO) {
167
count = -EPERM;
168
goto fail;
169
}
170
171
rc = kstrtoul(buf, 0, &value);
172
173
if (rc) {
174
count = -EINVAL;
175
goto fail;
176
}
177
178
hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, value);
179
goya->ic_clk = value;
180
181
fail:
182
return count;
183
}
184
185
static ssize_t mme_clk_curr_show(struct device *dev,
186
struct device_attribute *attr, char *buf)
187
{
188
struct hl_device *hdev = dev_get_drvdata(dev);
189
long value;
190
191
if (!hl_device_operational(hdev, NULL))
192
return -ENODEV;
193
194
value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, true);
195
196
if (value < 0)
197
return value;
198
199
return sprintf(buf, "%lu\n", value);
200
}
201
202
static ssize_t tpc_clk_curr_show(struct device *dev,
203
struct device_attribute *attr, char *buf)
204
{
205
struct hl_device *hdev = dev_get_drvdata(dev);
206
long value;
207
208
if (!hl_device_operational(hdev, NULL))
209
return -ENODEV;
210
211
value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
212
213
if (value < 0)
214
return value;
215
216
return sprintf(buf, "%lu\n", value);
217
}
218
219
static ssize_t ic_clk_curr_show(struct device *dev,
220
struct device_attribute *attr, char *buf)
221
{
222
struct hl_device *hdev = dev_get_drvdata(dev);
223
long value;
224
225
if (!hl_device_operational(hdev, NULL))
226
return -ENODEV;
227
228
value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, true);
229
230
if (value < 0)
231
return value;
232
233
return sprintf(buf, "%lu\n", value);
234
}
235
236
static ssize_t pm_mng_profile_show(struct device *dev,
237
struct device_attribute *attr, char *buf)
238
{
239
struct hl_device *hdev = dev_get_drvdata(dev);
240
struct goya_device *goya = hdev->asic_specific;
241
242
if (!hl_device_operational(hdev, NULL))
243
return -ENODEV;
244
245
return sprintf(buf, "%s\n",
246
(goya->pm_mng_profile == PM_AUTO) ? "auto" :
247
(goya->pm_mng_profile == PM_MANUAL) ? "manual" :
248
"unknown");
249
}
250
251
static ssize_t pm_mng_profile_store(struct device *dev,
252
struct device_attribute *attr, const char *buf, size_t count)
253
{
254
struct hl_device *hdev = dev_get_drvdata(dev);
255
struct goya_device *goya = hdev->asic_specific;
256
257
if (!hl_device_operational(hdev, NULL)) {
258
count = -ENODEV;
259
goto out;
260
}
261
262
mutex_lock(&hdev->fpriv_list_lock);
263
264
if (hdev->is_compute_ctx_active) {
265
dev_err(hdev->dev,
266
"Can't change PM profile while compute context is opened on the device\n");
267
count = -EPERM;
268
goto unlock_mutex;
269
}
270
271
if (strncmp("auto", buf, strlen("auto")) == 0) {
272
/* Make sure we are in LOW PLL when changing modes */
273
if (goya->pm_mng_profile == PM_MANUAL) {
274
goya->curr_pll_profile = PLL_HIGH;
275
goya->pm_mng_profile = PM_AUTO;
276
goya_set_frequency(hdev, PLL_LOW);
277
}
278
} else if (strncmp("manual", buf, strlen("manual")) == 0) {
279
if (goya->pm_mng_profile == PM_AUTO) {
280
/* Must release the lock because the work thread also
281
* takes this lock. But before we release it, set
282
* the mode to manual so nothing will change if a user
283
* suddenly opens the device
284
*/
285
goya->pm_mng_profile = PM_MANUAL;
286
287
mutex_unlock(&hdev->fpriv_list_lock);
288
289
/* Flush the current work so we can return to the user
290
* knowing that he is the only one changing frequencies
291
*/
292
if (goya->goya_work)
293
flush_delayed_work(&goya->goya_work->work_freq);
294
295
return count;
296
}
297
} else {
298
dev_err(hdev->dev, "value should be auto or manual\n");
299
count = -EINVAL;
300
}
301
302
unlock_mutex:
303
mutex_unlock(&hdev->fpriv_list_lock);
304
out:
305
return count;
306
}
307
308
static ssize_t high_pll_show(struct device *dev, struct device_attribute *attr,
309
char *buf)
310
{
311
struct hl_device *hdev = dev_get_drvdata(dev);
312
313
if (!hl_device_operational(hdev, NULL))
314
return -ENODEV;
315
316
return sprintf(buf, "%u\n", hdev->high_pll);
317
}
318
319
static ssize_t high_pll_store(struct device *dev, struct device_attribute *attr,
320
const char *buf, size_t count)
321
{
322
struct hl_device *hdev = dev_get_drvdata(dev);
323
long value;
324
int rc;
325
326
if (!hl_device_operational(hdev, NULL)) {
327
count = -ENODEV;
328
goto out;
329
}
330
331
rc = kstrtoul(buf, 0, &value);
332
333
if (rc) {
334
count = -EINVAL;
335
goto out;
336
}
337
338
hdev->high_pll = value;
339
340
out:
341
return count;
342
}
343
344
static DEVICE_ATTR_RW(high_pll);
345
static DEVICE_ATTR_RW(ic_clk);
346
static DEVICE_ATTR_RO(ic_clk_curr);
347
static DEVICE_ATTR_RW(mme_clk);
348
static DEVICE_ATTR_RO(mme_clk_curr);
349
static DEVICE_ATTR_RW(pm_mng_profile);
350
static DEVICE_ATTR_RW(tpc_clk);
351
static DEVICE_ATTR_RO(tpc_clk_curr);
352
353
static struct attribute *goya_clk_dev_attrs[] = {
354
&dev_attr_high_pll.attr,
355
&dev_attr_ic_clk.attr,
356
&dev_attr_ic_clk_curr.attr,
357
&dev_attr_mme_clk.attr,
358
&dev_attr_mme_clk_curr.attr,
359
&dev_attr_pm_mng_profile.attr,
360
&dev_attr_tpc_clk.attr,
361
&dev_attr_tpc_clk_curr.attr,
362
NULL,
363
};
364
365
static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
366
{
367
struct hl_device *hdev = dev_get_drvdata(dev);
368
struct cpucp_info *cpucp_info;
369
370
cpucp_info = &hdev->asic_prop.cpucp_info;
371
372
return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
373
}
374
375
static DEVICE_ATTR_RO(infineon_ver);
376
377
static struct attribute *goya_vrm_dev_attrs[] = {
378
&dev_attr_infineon_ver.attr,
379
NULL,
380
};
381
382
void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
383
struct attribute_group *dev_vrm_attr_grp)
384
{
385
dev_clk_attr_grp->attrs = goya_clk_dev_attrs;
386
dev_vrm_attr_grp->attrs = goya_vrm_dev_attrs;
387
}
388
389