]> Git Repo - linux.git/blob - drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux.git] / drivers / gpu / drm / xe / xe_hw_engine_class_sysfs.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5
6 #include <drm/drm_managed.h>
7 #include <linux/kobject.h>
8 #include <linux/sysfs.h>
9
10 #include "xe_gt.h"
11 #include "xe_hw_engine_class_sysfs.h"
12
13 #define MAX_ENGINE_CLASS_NAME_LEN    16
14 static int xe_add_hw_engine_class_defaults(struct xe_device *xe,
15                                            struct kobject *parent);
16
17 /**
18  * xe_hw_engine_timeout_in_range - Helper to check if timeout is in range
19  * @timeout: timeout to validate
20  * @min: min value of valid range
21  * @max: max value of valid range
22  *
23  * This helper helps to validate if timeout is in min-max range of HW engine
24  * scheduler.
25  *
26  * Returns: Returns false value for failure and true for success.
27  */
28 bool xe_hw_engine_timeout_in_range(u64 timeout, u64 min, u64 max)
29 {
30         return timeout >= min && timeout <= max;
31 }
32
33 static void kobj_xe_hw_engine_release(struct kobject *kobj)
34 {
35         kfree(kobj);
36 }
37
38 static const struct kobj_type kobj_xe_hw_engine_type = {
39         .release = kobj_xe_hw_engine_release,
40         .sysfs_ops = &kobj_sysfs_ops
41 };
42
43 static ssize_t job_timeout_max_store(struct kobject *kobj,
44                                      struct kobj_attribute *attr,
45                                      const char *buf, size_t count)
46 {
47         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
48         u32 timeout;
49         int err;
50
51         err = kstrtou32(buf, 0, &timeout);
52         if (err)
53                 return err;
54
55         if (timeout < eclass->sched_props.job_timeout_min)
56                 return -EINVAL;
57
58         if (!xe_hw_engine_timeout_in_range(timeout,
59                                            XE_HW_ENGINE_JOB_TIMEOUT_MIN,
60                                            XE_HW_ENGINE_JOB_TIMEOUT_MAX))
61                 return -EINVAL;
62
63         WRITE_ONCE(eclass->sched_props.job_timeout_max, timeout);
64
65         return count;
66 }
67
68 static ssize_t job_timeout_max_show(struct kobject *kobj,
69                                     struct kobj_attribute *attr, char *buf)
70 {
71         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
72
73         return sprintf(buf, "%u\n", eclass->sched_props.job_timeout_max);
74 }
75
76 static struct kobj_attribute job_timeout_max_attr =
77 __ATTR(job_timeout_max, 0644, job_timeout_max_show, job_timeout_max_store);
78
79 static ssize_t job_timeout_min_store(struct kobject *kobj,
80                                      struct kobj_attribute *attr,
81                                      const char *buf, size_t count)
82 {
83         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
84         u32 timeout;
85         int err;
86
87         err = kstrtou32(buf, 0, &timeout);
88         if (err)
89                 return err;
90
91         if (timeout > eclass->sched_props.job_timeout_max)
92                 return -EINVAL;
93
94         if (!xe_hw_engine_timeout_in_range(timeout,
95                                            XE_HW_ENGINE_JOB_TIMEOUT_MIN,
96                                            XE_HW_ENGINE_JOB_TIMEOUT_MAX))
97                 return -EINVAL;
98
99         WRITE_ONCE(eclass->sched_props.job_timeout_min, timeout);
100
101         return count;
102 }
103
104 static ssize_t job_timeout_min_show(struct kobject *kobj,
105                                     struct kobj_attribute *attr, char *buf)
106 {
107         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
108
109         return sprintf(buf, "%u\n", eclass->sched_props.job_timeout_min);
110 }
111
112 static struct kobj_attribute job_timeout_min_attr =
113 __ATTR(job_timeout_min, 0644, job_timeout_min_show, job_timeout_min_store);
114
115 static ssize_t job_timeout_store(struct kobject *kobj,
116                                  struct kobj_attribute *attr,
117                                  const char *buf, size_t count)
118 {
119         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
120         u32 min = eclass->sched_props.job_timeout_min;
121         u32 max = eclass->sched_props.job_timeout_max;
122         u32 timeout;
123         int err;
124
125         err = kstrtou32(buf, 0, &timeout);
126         if (err)
127                 return err;
128
129         if (!xe_hw_engine_timeout_in_range(timeout, min, max))
130                 return -EINVAL;
131
132         WRITE_ONCE(eclass->sched_props.job_timeout_ms, timeout);
133
134         return count;
135 }
136
137 static ssize_t job_timeout_show(struct kobject *kobj,
138                                 struct kobj_attribute *attr, char *buf)
139 {
140         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
141
142         return sprintf(buf, "%u\n", eclass->sched_props.job_timeout_ms);
143 }
144
145 static struct kobj_attribute job_timeout_attr =
146 __ATTR(job_timeout_ms, 0644, job_timeout_show, job_timeout_store);
147
148 static ssize_t job_timeout_default(struct kobject *kobj,
149                                    struct kobj_attribute *attr, char *buf)
150 {
151         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
152
153         return sprintf(buf, "%u\n", eclass->defaults.job_timeout_ms);
154 }
155
156 static struct kobj_attribute job_timeout_def =
157 __ATTR(job_timeout_ms, 0444, job_timeout_default, NULL);
158
159 static ssize_t job_timeout_min_default(struct kobject *kobj,
160                                        struct kobj_attribute *attr, char *buf)
161 {
162         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
163
164         return sprintf(buf, "%u\n", eclass->defaults.job_timeout_min);
165 }
166
167 static struct kobj_attribute job_timeout_min_def =
168 __ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL);
169
170 static ssize_t job_timeout_max_default(struct kobject *kobj,
171                                        struct kobj_attribute *attr, char *buf)
172 {
173         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
174
175         return sprintf(buf, "%u\n", eclass->defaults.job_timeout_max);
176 }
177
178 static struct kobj_attribute job_timeout_max_def =
179 __ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL);
180
181 static ssize_t timeslice_duration_store(struct kobject *kobj,
182                                         struct kobj_attribute *attr,
183                                         const char *buf, size_t count)
184 {
185         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
186         u32 min = eclass->sched_props.timeslice_min;
187         u32 max = eclass->sched_props.timeslice_max;
188         u32 duration;
189         int err;
190
191         err = kstrtou32(buf, 0, &duration);
192         if (err)
193                 return err;
194
195         if (!xe_hw_engine_timeout_in_range(duration, min, max))
196                 return -EINVAL;
197
198         WRITE_ONCE(eclass->sched_props.timeslice_us, duration);
199
200         return count;
201 }
202
203 static ssize_t timeslice_duration_max_store(struct kobject *kobj,
204                                             struct kobj_attribute *attr,
205                                             const char *buf, size_t count)
206 {
207         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
208         u32 duration;
209         int err;
210
211         err = kstrtou32(buf, 0, &duration);
212         if (err)
213                 return err;
214
215         if (duration < eclass->sched_props.timeslice_min)
216                 return -EINVAL;
217
218         if (!xe_hw_engine_timeout_in_range(duration,
219                                            XE_HW_ENGINE_TIMESLICE_MIN,
220                                            XE_HW_ENGINE_TIMESLICE_MAX))
221                 return -EINVAL;
222
223         WRITE_ONCE(eclass->sched_props.timeslice_max, duration);
224
225         return count;
226 }
227
228 static ssize_t timeslice_duration_max_show(struct kobject *kobj,
229                                            struct kobj_attribute *attr,
230                                            char *buf)
231 {
232         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
233
234         return sprintf(buf, "%u\n", eclass->sched_props.timeslice_max);
235 }
236
237 static struct kobj_attribute timeslice_duration_max_attr =
238         __ATTR(timeslice_duration_max, 0644, timeslice_duration_max_show,
239                timeslice_duration_max_store);
240
241 static ssize_t timeslice_duration_min_store(struct kobject *kobj,
242                                             struct kobj_attribute *attr,
243                                             const char *buf, size_t count)
244 {
245         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
246         u32 duration;
247         int err;
248
249         err = kstrtou32(buf, 0, &duration);
250         if (err)
251                 return err;
252
253         if (duration > eclass->sched_props.timeslice_max)
254                 return -EINVAL;
255
256         if (!xe_hw_engine_timeout_in_range(duration,
257                                            XE_HW_ENGINE_TIMESLICE_MIN,
258                                            XE_HW_ENGINE_TIMESLICE_MAX))
259                 return -EINVAL;
260
261         WRITE_ONCE(eclass->sched_props.timeslice_min, duration);
262
263         return count;
264 }
265
266 static ssize_t timeslice_duration_min_show(struct kobject *kobj,
267                                            struct kobj_attribute *attr,
268                                            char *buf)
269 {
270         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
271
272         return sprintf(buf, "%u\n", eclass->sched_props.timeslice_min);
273 }
274
275 static struct kobj_attribute timeslice_duration_min_attr =
276         __ATTR(timeslice_duration_min, 0644, timeslice_duration_min_show,
277                timeslice_duration_min_store);
278
279 static ssize_t timeslice_duration_show(struct kobject *kobj,
280                                        struct kobj_attribute *attr, char *buf)
281 {
282         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
283
284         return sprintf(buf, "%u\n", eclass->sched_props.timeslice_us);
285 }
286
287 static struct kobj_attribute timeslice_duration_attr =
288         __ATTR(timeslice_duration_us, 0644, timeslice_duration_show,
289                timeslice_duration_store);
290
291 static ssize_t timeslice_default(struct kobject *kobj,
292                                  struct kobj_attribute *attr, char *buf)
293 {
294         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
295
296         return sprintf(buf, "%u\n", eclass->defaults.timeslice_us);
297 }
298
299 static struct kobj_attribute timeslice_duration_def =
300 __ATTR(timeslice_duration_us, 0444, timeslice_default, NULL);
301
302 static ssize_t timeslice_min_default(struct kobject *kobj,
303                                      struct kobj_attribute *attr, char *buf)
304 {
305         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
306
307         return sprintf(buf, "%u\n", eclass->defaults.timeslice_min);
308 }
309
310 static struct kobj_attribute timeslice_duration_min_def =
311 __ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL);
312
313 static ssize_t timeslice_max_default(struct kobject *kobj,
314                                      struct kobj_attribute *attr, char *buf)
315 {
316         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
317
318         return sprintf(buf, "%u\n", eclass->defaults.timeslice_max);
319 }
320
321 static struct kobj_attribute timeslice_duration_max_def =
322 __ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL);
323
324 static ssize_t preempt_timeout_store(struct kobject *kobj,
325                                      struct kobj_attribute *attr,
326                                      const char *buf, size_t count)
327 {
328         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
329         u32 min = eclass->sched_props.preempt_timeout_min;
330         u32 max = eclass->sched_props.preempt_timeout_max;
331         u32 timeout;
332         int err;
333
334         err = kstrtou32(buf, 0, &timeout);
335         if (err)
336                 return err;
337
338         if (!xe_hw_engine_timeout_in_range(timeout, min, max))
339                 return -EINVAL;
340
341         WRITE_ONCE(eclass->sched_props.preempt_timeout_us, timeout);
342
343         return count;
344 }
345
346 static ssize_t preempt_timeout_show(struct kobject *kobj,
347                                     struct kobj_attribute *attr, char *buf)
348 {
349         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
350
351         return sprintf(buf, "%u\n", eclass->sched_props.preempt_timeout_us);
352 }
353
354 static struct kobj_attribute preempt_timeout_attr =
355 __ATTR(preempt_timeout_us, 0644, preempt_timeout_show, preempt_timeout_store);
356
357 static ssize_t preempt_timeout_default(struct kobject *kobj,
358                                        struct kobj_attribute *attr,
359                                        char *buf)
360 {
361         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
362
363         return sprintf(buf, "%u\n", eclass->defaults.preempt_timeout_us);
364 }
365
366 static struct kobj_attribute preempt_timeout_def =
367 __ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL);
368
369 static ssize_t preempt_timeout_min_default(struct kobject *kobj,
370                                            struct kobj_attribute *attr,
371                                            char *buf)
372 {
373         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
374
375         return sprintf(buf, "%u\n", eclass->defaults.preempt_timeout_min);
376 }
377
378 static struct kobj_attribute preempt_timeout_min_def =
379 __ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default, NULL);
380
381 static ssize_t preempt_timeout_max_default(struct kobject *kobj,
382                                            struct kobj_attribute *attr,
383                                            char *buf)
384 {
385         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
386
387         return sprintf(buf, "%u\n", eclass->defaults.preempt_timeout_max);
388 }
389
390 static struct kobj_attribute preempt_timeout_max_def =
391 __ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default, NULL);
392
393 static ssize_t preempt_timeout_max_store(struct kobject *kobj,
394                                          struct kobj_attribute *attr,
395                                          const char *buf, size_t count)
396 {
397         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
398         u32 timeout;
399         int err;
400
401         err = kstrtou32(buf, 0, &timeout);
402         if (err)
403                 return err;
404
405         if (timeout < eclass->sched_props.preempt_timeout_min)
406                 return -EINVAL;
407
408         if (!xe_hw_engine_timeout_in_range(timeout,
409                                            XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
410                                            XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
411                 return -EINVAL;
412
413         WRITE_ONCE(eclass->sched_props.preempt_timeout_max, timeout);
414
415         return count;
416 }
417
418 static ssize_t preempt_timeout_max_show(struct kobject *kobj,
419                                         struct kobj_attribute *attr, char *buf)
420 {
421         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
422
423         return sprintf(buf, "%u\n", eclass->sched_props.preempt_timeout_max);
424 }
425
426 static struct kobj_attribute preempt_timeout_max_attr =
427         __ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show,
428                preempt_timeout_max_store);
429
430 static ssize_t preempt_timeout_min_store(struct kobject *kobj,
431                                          struct kobj_attribute *attr,
432                                          const char *buf, size_t count)
433 {
434         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
435         u32 timeout;
436         int err;
437
438         err = kstrtou32(buf, 0, &timeout);
439         if (err)
440                 return err;
441
442         if (timeout > eclass->sched_props.preempt_timeout_max)
443                 return -EINVAL;
444
445         if (!xe_hw_engine_timeout_in_range(timeout,
446                                            XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
447                                            XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
448                 return -EINVAL;
449
450         WRITE_ONCE(eclass->sched_props.preempt_timeout_min, timeout);
451
452         return count;
453 }
454
455 static ssize_t preempt_timeout_min_show(struct kobject *kobj,
456                                         struct kobj_attribute *attr, char *buf)
457 {
458         struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
459
460         return sprintf(buf, "%u\n", eclass->sched_props.preempt_timeout_min);
461 }
462
463 static struct kobj_attribute preempt_timeout_min_attr =
464         __ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show,
465                preempt_timeout_min_store);
466
467 static const struct attribute *defaults[] = {
468         &job_timeout_def.attr,
469         &job_timeout_min_def.attr,
470         &job_timeout_max_def.attr,
471         &timeslice_duration_def.attr,
472         &timeslice_duration_min_def.attr,
473         &timeslice_duration_max_def.attr,
474         &preempt_timeout_def.attr,
475         &preempt_timeout_min_def.attr,
476         &preempt_timeout_max_def.attr,
477         NULL
478 };
479
480 static const struct attribute *files[] = {
481         &job_timeout_attr.attr,
482         &job_timeout_min_attr.attr,
483         &job_timeout_max_attr.attr,
484         &timeslice_duration_attr.attr,
485         &timeslice_duration_min_attr.attr,
486         &timeslice_duration_max_attr.attr,
487         &preempt_timeout_attr.attr,
488         &preempt_timeout_min_attr.attr,
489         &preempt_timeout_max_attr.attr,
490         NULL
491 };
492
493 static void kobj_xe_hw_engine_class_fini(struct drm_device *drm, void *arg)
494 {
495         struct kobject *kobj = arg;
496
497         sysfs_remove_files(kobj, files);
498         kobject_put(kobj);
499 }
500
501         static struct kobj_eclass *
502 kobj_xe_hw_engine_class(struct xe_device *xe, struct kobject *parent, char *name)
503 {
504         struct kobj_eclass *keclass;
505         int err = 0;
506
507         keclass = kzalloc(sizeof(*keclass), GFP_KERNEL);
508         if (!keclass)
509                 return NULL;
510
511         kobject_init(&keclass->base, &kobj_xe_hw_engine_type);
512         if (kobject_add(&keclass->base, parent, "%s", name)) {
513                 kobject_put(&keclass->base);
514                 return NULL;
515         }
516
517         err = drmm_add_action_or_reset(&xe->drm, kobj_xe_hw_engine_class_fini,
518                                        &keclass->base);
519         if (err)
520                 drm_warn(&xe->drm,
521                          "%s: drmm_add_action_or_reset failed, err: %d\n",
522                          __func__, err);
523         return keclass;
524 }
525
526 static void hw_engine_class_defaults_fini(struct drm_device *drm, void *arg)
527 {
528         struct kobject *kobj = arg;
529
530         sysfs_remove_files(kobj, defaults);
531         kobject_put(kobj);
532 }
533
534 static int xe_add_hw_engine_class_defaults(struct xe_device *xe,
535                                            struct kobject *parent)
536 {
537         struct kobject *kobj;
538         int err = 0;
539
540         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
541         if (!kobj)
542                 return -ENOMEM;
543
544         kobject_init(kobj, &kobj_xe_hw_engine_type);
545         err = kobject_add(kobj, parent, "%s", ".defaults");
546         if (err)
547                 goto err_object;
548
549         err = sysfs_create_files(kobj, defaults);
550         if (err)
551                 goto err_object;
552
553         err = drmm_add_action_or_reset(&xe->drm, hw_engine_class_defaults_fini,
554                                        kobj);
555         if (err)
556                 drm_warn(&xe->drm,
557                          "%s: drmm_add_action_or_reset failed, err: %d\n",
558                          __func__, err);
559         return err;
560 err_object:
561         kobject_put(kobj);
562         return err;
563 }
564
565 static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj)
566 {
567         kfree(kobj);
568 }
569
570 static const struct kobj_type xe_hw_engine_sysfs_kobj_type = {
571         .release = xe_hw_engine_sysfs_kobj_release,
572         .sysfs_ops = &kobj_sysfs_ops,
573 };
574
575 static void hw_engine_class_sysfs_fini(struct drm_device *drm, void *arg)
576 {
577         struct kobject *kobj = arg;
578
579         kobject_put(kobj);
580 }
581
582 /**
583  * xe_hw_engine_class_sysfs_init - Init HW engine classes on GT.
584  * @gt: Xe GT.
585  *
586  * This routine creates sysfs for HW engine classes and adds methods
587  * to get/set different scheduling properties for HW engines class.
588  *
589  * Returns: Returns error value for failure and 0 for success.
590  */
591 int xe_hw_engine_class_sysfs_init(struct xe_gt *gt)
592 {
593         struct xe_device *xe = gt_to_xe(gt);
594         struct xe_hw_engine *hwe;
595         enum xe_hw_engine_id id;
596         struct kobject *kobj;
597         u16 class_mask = 0;
598         int err = 0;
599
600         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
601         if (!kobj)
602                 return -ENOMEM;
603
604         kobject_init(kobj, &xe_hw_engine_sysfs_kobj_type);
605
606         err = kobject_add(kobj, gt->sysfs, "engines");
607         if (err)
608                 goto err_object;
609
610         for_each_hw_engine(hwe, gt, id) {
611                 char name[MAX_ENGINE_CLASS_NAME_LEN];
612                 struct kobj_eclass *keclass;
613
614                 if (hwe->class == XE_ENGINE_CLASS_OTHER ||
615                     hwe->class == XE_ENGINE_CLASS_MAX)
616                         continue;
617
618                 if ((class_mask >> hwe->class) & 1)
619                         continue;
620
621                 class_mask |= 1 << hwe->class;
622
623                 switch (hwe->class) {
624                 case XE_ENGINE_CLASS_RENDER:
625                         strcpy(name, "rcs");
626                         break;
627                 case XE_ENGINE_CLASS_VIDEO_DECODE:
628                         strcpy(name, "vcs");
629                         break;
630                 case XE_ENGINE_CLASS_VIDEO_ENHANCE:
631                         strcpy(name, "vecs");
632                         break;
633                 case XE_ENGINE_CLASS_COPY:
634                         strcpy(name, "bcs");
635                         break;
636                 case XE_ENGINE_CLASS_COMPUTE:
637                         strcpy(name, "ccs");
638                         break;
639                 default:
640                         err = -EINVAL;
641                         goto err_object;
642                 }
643
644                 keclass = kobj_xe_hw_engine_class(xe, kobj, name);
645                 if (!keclass) {
646                         err = -EINVAL;
647                         goto err_object;
648                 }
649
650                 keclass->eclass = hwe->eclass;
651                 err = xe_add_hw_engine_class_defaults(xe, &keclass->base);
652                 if (err) {
653                         drm_warn(&xe->drm,
654                                  "Add .defaults to engines failed!, err: %d\n",
655                                  err);
656                         goto err_object;
657                 }
658
659                 err = sysfs_create_files(&keclass->base, files);
660                 if (err)
661                         goto err_object;
662         }
663
664         err = drmm_add_action_or_reset(&xe->drm, hw_engine_class_sysfs_fini,
665                                        kobj);
666         if (err)
667                 drm_warn(&xe->drm,
668                          "%s: drmm_add_action_or_reset failed, err: %d\n",
669                          __func__, err);
670
671         return err;
672 err_object:
673         kobject_put(kobj);
674         return err;
675 }
This page took 0.07611 seconds and 4 git commands to generate.