]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/hwtracing/intel_th/core.c
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / drivers / hwtracing / intel_th / core.c
1 /*
2  * Intel(R) Trace Hub driver core
3  *
4  * Copyright (C) 2014-2015 Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15
16 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
17
18 #include <linux/types.h>
19 #include <linux/module.h>
20 #include <linux/device.h>
21 #include <linux/sysfs.h>
22 #include <linux/kdev_t.h>
23 #include <linux/debugfs.h>
24 #include <linux/idr.h>
25 #include <linux/pci.h>
26 #include <linux/pm_runtime.h>
27 #include <linux/dma-mapping.h>
28
29 #include "intel_th.h"
30 #include "debug.h"
31
32 static DEFINE_IDA(intel_th_ida);
33
34 static int intel_th_match(struct device *dev, struct device_driver *driver)
35 {
36         struct intel_th_driver *thdrv = to_intel_th_driver(driver);
37         struct intel_th_device *thdev = to_intel_th_device(dev);
38
39         if (thdev->type == INTEL_TH_SWITCH &&
40             (!thdrv->enable || !thdrv->disable))
41                 return 0;
42
43         return !strcmp(thdev->name, driver->name);
44 }
45
46 static int intel_th_child_remove(struct device *dev, void *data)
47 {
48         device_release_driver(dev);
49
50         return 0;
51 }
52
53 static int intel_th_probe(struct device *dev)
54 {
55         struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
56         struct intel_th_device *thdev = to_intel_th_device(dev);
57         struct intel_th_driver *hubdrv;
58         struct intel_th_device *hub = NULL;
59         int ret;
60
61         if (thdev->type == INTEL_TH_SWITCH)
62                 hub = thdev;
63         else if (dev->parent)
64                 hub = to_intel_th_device(dev->parent);
65
66         if (!hub || !hub->dev.driver)
67                 return -EPROBE_DEFER;
68
69         hubdrv = to_intel_th_driver(hub->dev.driver);
70
71         pm_runtime_set_active(dev);
72         pm_runtime_no_callbacks(dev);
73         pm_runtime_enable(dev);
74
75         ret = thdrv->probe(to_intel_th_device(dev));
76         if (ret)
77                 goto out_pm;
78
79         if (thdrv->attr_group) {
80                 ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group);
81                 if (ret)
82                         goto out;
83         }
84
85         if (thdev->type == INTEL_TH_OUTPUT &&
86             !intel_th_output_assigned(thdev))
87                 /* does not talk to hardware */
88                 ret = hubdrv->assign(hub, thdev);
89
90 out:
91         if (ret)
92                 thdrv->remove(thdev);
93
94 out_pm:
95         if (ret)
96                 pm_runtime_disable(dev);
97
98         return ret;
99 }
100
101 static int intel_th_remove(struct device *dev)
102 {
103         struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
104         struct intel_th_device *thdev = to_intel_th_device(dev);
105         struct intel_th_device *hub = to_intel_th_device(dev->parent);
106         int err;
107
108         if (thdev->type == INTEL_TH_SWITCH) {
109                 err = device_for_each_child(dev, thdev, intel_th_child_remove);
110                 if (err)
111                         return err;
112         }
113
114         if (thdrv->attr_group)
115                 sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group);
116
117         pm_runtime_get_sync(dev);
118
119         thdrv->remove(thdev);
120
121         if (intel_th_output_assigned(thdev)) {
122                 struct intel_th_driver *hubdrv =
123                         to_intel_th_driver(dev->parent->driver);
124
125                 if (hub->dev.driver)
126                         /* does not talk to hardware */
127                         hubdrv->unassign(hub, thdev);
128         }
129
130         pm_runtime_disable(dev);
131         pm_runtime_set_active(dev);
132         pm_runtime_enable(dev);
133
134         return 0;
135 }
136
137 static struct bus_type intel_th_bus = {
138         .name           = "intel_th",
139         .dev_attrs      = NULL,
140         .match          = intel_th_match,
141         .probe          = intel_th_probe,
142         .remove         = intel_th_remove,
143 };
144
145 static void intel_th_device_free(struct intel_th_device *thdev);
146
147 static void intel_th_device_release(struct device *dev)
148 {
149         intel_th_device_free(to_intel_th_device(dev));
150 }
151
152 static struct device_type intel_th_source_device_type = {
153         .name           = "intel_th_source_device",
154         .release        = intel_th_device_release,
155 };
156
157 static struct intel_th *to_intel_th(struct intel_th_device *thdev)
158 {
159         /*
160          * subdevice tree is flat: if this one is not a switch, its
161          * parent must be
162          */
163         if (thdev->type != INTEL_TH_SWITCH)
164                 thdev = to_intel_th_hub(thdev);
165
166         if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH))
167                 return NULL;
168
169         return dev_get_drvdata(thdev->dev.parent);
170 }
171
172 static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
173                                      kuid_t *uid, kgid_t *gid)
174 {
175         struct intel_th_device *thdev = to_intel_th_device(dev);
176         struct intel_th *th = to_intel_th(thdev);
177         char *node;
178
179         if (thdev->id >= 0)
180                 node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id,
181                                  thdev->name, thdev->id);
182         else
183                 node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id,
184                                  thdev->name);
185
186         return node;
187 }
188
189 static ssize_t port_show(struct device *dev, struct device_attribute *attr,
190                          char *buf)
191 {
192         struct intel_th_device *thdev = to_intel_th_device(dev);
193
194         if (thdev->output.port >= 0)
195                 return scnprintf(buf, PAGE_SIZE, "%u\n", thdev->output.port);
196
197         return scnprintf(buf, PAGE_SIZE, "unassigned\n");
198 }
199
200 static DEVICE_ATTR_RO(port);
201
202 static int intel_th_output_activate(struct intel_th_device *thdev)
203 {
204         struct intel_th_driver *thdrv =
205                 to_intel_th_driver_or_null(thdev->dev.driver);
206         int ret = 0;
207
208         if (!thdrv)
209                 return -ENODEV;
210
211         if (!try_module_get(thdrv->driver.owner))
212                 return -ENODEV;
213
214         pm_runtime_get_sync(&thdev->dev);
215
216         if (thdrv->activate)
217                 ret = thdrv->activate(thdev);
218         else
219                 intel_th_trace_enable(thdev);
220
221         if (ret)
222                 pm_runtime_put(&thdev->dev);
223
224         return ret;
225 }
226
227 static void intel_th_output_deactivate(struct intel_th_device *thdev)
228 {
229         struct intel_th_driver *thdrv =
230                 to_intel_th_driver_or_null(thdev->dev.driver);
231
232         if (!thdrv)
233                 return;
234
235         if (thdrv->deactivate)
236                 thdrv->deactivate(thdev);
237         else
238                 intel_th_trace_disable(thdev);
239
240         pm_runtime_put(&thdev->dev);
241         module_put(thdrv->driver.owner);
242 }
243
244 static ssize_t active_show(struct device *dev, struct device_attribute *attr,
245                            char *buf)
246 {
247         struct intel_th_device *thdev = to_intel_th_device(dev);
248
249         return scnprintf(buf, PAGE_SIZE, "%d\n", thdev->output.active);
250 }
251
252 static ssize_t active_store(struct device *dev, struct device_attribute *attr,
253                             const char *buf, size_t size)
254 {
255         struct intel_th_device *thdev = to_intel_th_device(dev);
256         unsigned long val;
257         int ret;
258
259         ret = kstrtoul(buf, 10, &val);
260         if (ret)
261                 return ret;
262
263         if (!!val != thdev->output.active) {
264                 if (val)
265                         ret = intel_th_output_activate(thdev);
266                 else
267                         intel_th_output_deactivate(thdev);
268         }
269
270         return ret ? ret : size;
271 }
272
273 static DEVICE_ATTR_RW(active);
274
275 static struct attribute *intel_th_output_attrs[] = {
276         &dev_attr_port.attr,
277         &dev_attr_active.attr,
278         NULL,
279 };
280
281 ATTRIBUTE_GROUPS(intel_th_output);
282
283 static struct device_type intel_th_output_device_type = {
284         .name           = "intel_th_output_device",
285         .groups         = intel_th_output_groups,
286         .release        = intel_th_device_release,
287         .devnode        = intel_th_output_devnode,
288 };
289
290 static struct device_type intel_th_switch_device_type = {
291         .name           = "intel_th_switch_device",
292         .release        = intel_th_device_release,
293 };
294
295 static struct device_type *intel_th_device_type[] = {
296         [INTEL_TH_SOURCE]       = &intel_th_source_device_type,
297         [INTEL_TH_OUTPUT]       = &intel_th_output_device_type,
298         [INTEL_TH_SWITCH]       = &intel_th_switch_device_type,
299 };
300
301 int intel_th_driver_register(struct intel_th_driver *thdrv)
302 {
303         if (!thdrv->probe || !thdrv->remove)
304                 return -EINVAL;
305
306         thdrv->driver.bus = &intel_th_bus;
307
308         return driver_register(&thdrv->driver);
309 }
310 EXPORT_SYMBOL_GPL(intel_th_driver_register);
311
312 void intel_th_driver_unregister(struct intel_th_driver *thdrv)
313 {
314         driver_unregister(&thdrv->driver);
315 }
316 EXPORT_SYMBOL_GPL(intel_th_driver_unregister);
317
318 static struct intel_th_device *
319 intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name,
320                       int id)
321 {
322         struct device *parent;
323         struct intel_th_device *thdev;
324
325         if (type == INTEL_TH_SWITCH)
326                 parent = th->dev;
327         else
328                 parent = &th->hub->dev;
329
330         thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL);
331         if (!thdev)
332                 return NULL;
333
334         thdev->id = id;
335         thdev->type = type;
336
337         strcpy(thdev->name, name);
338         device_initialize(&thdev->dev);
339         thdev->dev.bus = &intel_th_bus;
340         thdev->dev.type = intel_th_device_type[type];
341         thdev->dev.parent = parent;
342         thdev->dev.dma_mask = parent->dma_mask;
343         thdev->dev.dma_parms = parent->dma_parms;
344         dma_set_coherent_mask(&thdev->dev, parent->coherent_dma_mask);
345         if (id >= 0)
346                 dev_set_name(&thdev->dev, "%d-%s%d", th->id, name, id);
347         else
348                 dev_set_name(&thdev->dev, "%d-%s", th->id, name);
349
350         return thdev;
351 }
352
353 static int intel_th_device_add_resources(struct intel_th_device *thdev,
354                                          struct resource *res, int nres)
355 {
356         struct resource *r;
357
358         r = kmemdup(res, sizeof(*res) * nres, GFP_KERNEL);
359         if (!r)
360                 return -ENOMEM;
361
362         thdev->resource = r;
363         thdev->num_resources = nres;
364
365         return 0;
366 }
367
368 static void intel_th_device_remove(struct intel_th_device *thdev)
369 {
370         device_del(&thdev->dev);
371         put_device(&thdev->dev);
372 }
373
374 static void intel_th_device_free(struct intel_th_device *thdev)
375 {
376         kfree(thdev->resource);
377         kfree(thdev);
378 }
379
380 /*
381  * Intel(R) Trace Hub subdevices
382  */
383 static struct intel_th_subdevice {
384         const char              *name;
385         struct resource         res[3];
386         unsigned                nres;
387         unsigned                type;
388         unsigned                otype;
389         unsigned                scrpd;
390         int                     id;
391 } intel_th_subdevices[TH_SUBDEVICE_MAX] = {
392         {
393                 .nres   = 1,
394                 .res    = {
395                         {
396                                 .start  = REG_GTH_OFFSET,
397                                 .end    = REG_GTH_OFFSET + REG_GTH_LENGTH - 1,
398                                 .flags  = IORESOURCE_MEM,
399                         },
400                 },
401                 .name   = "gth",
402                 .type   = INTEL_TH_SWITCH,
403                 .id     = -1,
404         },
405         {
406                 .nres   = 2,
407                 .res    = {
408                         {
409                                 .start  = REG_MSU_OFFSET,
410                                 .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
411                                 .flags  = IORESOURCE_MEM,
412                         },
413                         {
414                                 .start  = BUF_MSU_OFFSET,
415                                 .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
416                                 .flags  = IORESOURCE_MEM,
417                         },
418                 },
419                 .name   = "msc",
420                 .id     = 0,
421                 .type   = INTEL_TH_OUTPUT,
422                 .otype  = GTH_MSU,
423                 .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
424         },
425         {
426                 .nres   = 2,
427                 .res    = {
428                         {
429                                 .start  = REG_MSU_OFFSET,
430                                 .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
431                                 .flags  = IORESOURCE_MEM,
432                         },
433                         {
434                                 .start  = BUF_MSU_OFFSET,
435                                 .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
436                                 .flags  = IORESOURCE_MEM,
437                         },
438                 },
439                 .name   = "msc",
440                 .id     = 1,
441                 .type   = INTEL_TH_OUTPUT,
442                 .otype  = GTH_MSU,
443                 .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
444         },
445         {
446                 .nres   = 2,
447                 .res    = {
448                         {
449                                 .start  = REG_STH_OFFSET,
450                                 .end    = REG_STH_OFFSET + REG_STH_LENGTH - 1,
451                                 .flags  = IORESOURCE_MEM,
452                         },
453                         {
454                                 .start  = TH_MMIO_SW,
455                                 .end    = 0,
456                                 .flags  = IORESOURCE_MEM,
457                         },
458                 },
459                 .id     = -1,
460                 .name   = "sth",
461                 .type   = INTEL_TH_SOURCE,
462         },
463         {
464                 .nres   = 1,
465                 .res    = {
466                         {
467                                 .start  = REG_PTI_OFFSET,
468                                 .end    = REG_PTI_OFFSET + REG_PTI_LENGTH - 1,
469                                 .flags  = IORESOURCE_MEM,
470                         },
471                 },
472                 .id     = -1,
473                 .name   = "pti",
474                 .type   = INTEL_TH_OUTPUT,
475                 .otype  = GTH_PTI,
476                 .scrpd  = SCRPD_PTI_IS_PRIM_DEST,
477         },
478         {
479                 .nres   = 1,
480                 .res    = {
481                         {
482                                 .start  = REG_DCIH_OFFSET,
483                                 .end    = REG_DCIH_OFFSET + REG_DCIH_LENGTH - 1,
484                                 .flags  = IORESOURCE_MEM,
485                         },
486                 },
487                 .id     = -1,
488                 .name   = "dcih",
489                 .type   = INTEL_TH_OUTPUT,
490         },
491 };
492
493 #ifdef CONFIG_MODULES
494 static void __intel_th_request_hub_module(struct work_struct *work)
495 {
496         struct intel_th *th = container_of(work, struct intel_th,
497                                            request_module_work);
498
499         request_module("intel_th_%s", th->hub->name);
500 }
501
502 static int intel_th_request_hub_module(struct intel_th *th)
503 {
504         INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
505         schedule_work(&th->request_module_work);
506
507         return 0;
508 }
509
510 static void intel_th_request_hub_module_flush(struct intel_th *th)
511 {
512         flush_work(&th->request_module_work);
513 }
514 #else
515 static inline int intel_th_request_hub_module(struct intel_th *th)
516 {
517         return -EINVAL;
518 }
519
520 static inline void intel_th_request_hub_module_flush(struct intel_th *th)
521 {
522 }
523 #endif /* CONFIG_MODULES */
524
525 static int intel_th_populate(struct intel_th *th, struct resource *devres,
526                              unsigned int ndevres, int irq)
527 {
528         struct resource res[3];
529         unsigned int req = 0;
530         int i, err;
531
532         /* create devices for each intel_th_subdevice */
533         for (i = 0; i < ARRAY_SIZE(intel_th_subdevices); i++) {
534                 struct intel_th_subdevice *subdev = &intel_th_subdevices[i];
535                 struct intel_th_device *thdev;
536                 int r;
537
538                 thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
539                                               subdev->id);
540                 if (!thdev) {
541                         err = -ENOMEM;
542                         goto kill_subdevs;
543                 }
544
545                 memcpy(res, subdev->res,
546                        sizeof(struct resource) * subdev->nres);
547
548                 for (r = 0; r < subdev->nres; r++) {
549                         int bar = TH_MMIO_CONFIG;
550
551                         /*
552                          * Take .end == 0 to mean 'take the whole bar',
553                          * .start then tells us which bar it is. Default to
554                          * TH_MMIO_CONFIG.
555                          */
556                         if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
557                                 bar = res[r].start;
558                                 res[r].start = 0;
559                                 res[r].end = resource_size(&devres[bar]) - 1;
560                         }
561
562                         if (res[r].flags & IORESOURCE_MEM) {
563                                 res[r].start    += devres[bar].start;
564                                 res[r].end      += devres[bar].start;
565
566                                 dev_dbg(th->dev, "%s:%d @ %pR\n",
567                                         subdev->name, r, &res[r]);
568                         } else if (res[r].flags & IORESOURCE_IRQ) {
569                                 res[r].start    = irq;
570                         }
571                 }
572
573                 err = intel_th_device_add_resources(thdev, res, subdev->nres);
574                 if (err) {
575                         put_device(&thdev->dev);
576                         goto kill_subdevs;
577                 }
578
579                 if (subdev->type == INTEL_TH_OUTPUT) {
580                         thdev->dev.devt = MKDEV(th->major, i);
581                         thdev->output.type = subdev->otype;
582                         thdev->output.port = -1;
583                         thdev->output.scratchpad = subdev->scrpd;
584                 }
585
586                 err = device_add(&thdev->dev);
587                 if (err) {
588                         put_device(&thdev->dev);
589                         goto kill_subdevs;
590                 }
591
592                 /* need switch driver to be loaded to enumerate the rest */
593                 if (subdev->type == INTEL_TH_SWITCH && !req) {
594                         th->hub = thdev;
595                         err = intel_th_request_hub_module(th);
596                         if (!err)
597                                 req++;
598                 }
599
600                 th->thdev[i] = thdev;
601         }
602
603         return 0;
604
605 kill_subdevs:
606         for (i-- ; i >= 0; i--)
607                 intel_th_device_remove(th->thdev[i]);
608
609         return err;
610 }
611
612 static int match_devt(struct device *dev, void *data)
613 {
614         dev_t devt = (dev_t)(unsigned long)data;
615
616         return dev->devt == devt;
617 }
618
619 static int intel_th_output_open(struct inode *inode, struct file *file)
620 {
621         const struct file_operations *fops;
622         struct intel_th_driver *thdrv;
623         struct device *dev;
624         int err;
625
626         dev = bus_find_device(&intel_th_bus, NULL,
627                               (void *)(unsigned long)inode->i_rdev,
628                               match_devt);
629         if (!dev || !dev->driver)
630                 return -ENODEV;
631
632         thdrv = to_intel_th_driver(dev->driver);
633         fops = fops_get(thdrv->fops);
634         if (!fops)
635                 return -ENODEV;
636
637         replace_fops(file, fops);
638
639         file->private_data = to_intel_th_device(dev);
640
641         if (file->f_op->open) {
642                 err = file->f_op->open(inode, file);
643                 return err;
644         }
645
646         return 0;
647 }
648
649 static const struct file_operations intel_th_output_fops = {
650         .open   = intel_th_output_open,
651         .llseek = noop_llseek,
652 };
653
654 /**
655  * intel_th_alloc() - allocate a new Intel TH device and its subdevices
656  * @dev:        parent device
657  * @devres:     parent's resources
658  * @ndevres:    number of resources
659  * @irq:        irq number
660  */
661 struct intel_th *
662 intel_th_alloc(struct device *dev, struct resource *devres,
663                unsigned int ndevres, int irq)
664 {
665         struct intel_th *th;
666         int err;
667
668         th = kzalloc(sizeof(*th), GFP_KERNEL);
669         if (!th)
670                 return ERR_PTR(-ENOMEM);
671
672         th->id = ida_simple_get(&intel_th_ida, 0, 0, GFP_KERNEL);
673         if (th->id < 0) {
674                 err = th->id;
675                 goto err_alloc;
676         }
677
678         th->major = __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS,
679                                       "intel_th/output", &intel_th_output_fops);
680         if (th->major < 0) {
681                 err = th->major;
682                 goto err_ida;
683         }
684         th->dev = dev;
685
686         dev_set_drvdata(dev, th);
687
688         pm_runtime_no_callbacks(dev);
689         pm_runtime_put(dev);
690         pm_runtime_allow(dev);
691
692         err = intel_th_populate(th, devres, ndevres, irq);
693         if (err)
694                 goto err_chrdev;
695
696         return th;
697
698 err_chrdev:
699         pm_runtime_forbid(dev);
700
701         __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
702                             "intel_th/output");
703
704 err_ida:
705         ida_simple_remove(&intel_th_ida, th->id);
706
707 err_alloc:
708         kfree(th);
709
710         return ERR_PTR(err);
711 }
712 EXPORT_SYMBOL_GPL(intel_th_alloc);
713
714 void intel_th_free(struct intel_th *th)
715 {
716         int i;
717
718         intel_th_request_hub_module_flush(th);
719         for (i = 0; i < TH_SUBDEVICE_MAX; i++)
720                 if (th->thdev[i] != th->hub)
721                         intel_th_device_remove(th->thdev[i]);
722
723         intel_th_device_remove(th->hub);
724
725         pm_runtime_get_sync(th->dev);
726         pm_runtime_forbid(th->dev);
727
728         __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
729                             "intel_th/output");
730
731         ida_simple_remove(&intel_th_ida, th->id);
732
733         kfree(th);
734 }
735 EXPORT_SYMBOL_GPL(intel_th_free);
736
737 /**
738  * intel_th_trace_enable() - enable tracing for an output device
739  * @thdev:      output device that requests tracing be enabled
740  */
741 int intel_th_trace_enable(struct intel_th_device *thdev)
742 {
743         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
744         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
745
746         if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
747                 return -EINVAL;
748
749         if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
750                 return -EINVAL;
751
752         pm_runtime_get_sync(&thdev->dev);
753         hubdrv->enable(hub, &thdev->output);
754
755         return 0;
756 }
757 EXPORT_SYMBOL_GPL(intel_th_trace_enable);
758
759 /**
760  * intel_th_trace_disable() - disable tracing for an output device
761  * @thdev:      output device that requests tracing be disabled
762  */
763 int intel_th_trace_disable(struct intel_th_device *thdev)
764 {
765         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
766         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
767
768         WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH);
769         if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
770                 return -EINVAL;
771
772         hubdrv->disable(hub, &thdev->output);
773         pm_runtime_put(&thdev->dev);
774
775         return 0;
776 }
777 EXPORT_SYMBOL_GPL(intel_th_trace_disable);
778
779 int intel_th_set_output(struct intel_th_device *thdev,
780                         unsigned int master)
781 {
782         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
783         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
784
785         if (!hubdrv->set_output)
786                 return -ENOTSUPP;
787
788         return hubdrv->set_output(hub, master);
789 }
790 EXPORT_SYMBOL_GPL(intel_th_set_output);
791
792 static int __init intel_th_init(void)
793 {
794         intel_th_debug_init();
795
796         return bus_register(&intel_th_bus);
797 }
798 subsys_initcall(intel_th_init);
799
800 static void __exit intel_th_exit(void)
801 {
802         intel_th_debug_done();
803
804         bus_unregister(&intel_th_bus);
805 }
806 module_exit(intel_th_exit);
807
808 MODULE_LICENSE("GPL v2");
809 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
810 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");