GNU Linux-libre 4.9.337-gnu1
[releases.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                 module_put(thdrv->driver.owner);
224         }
225
226         return ret;
227 }
228
229 static void intel_th_output_deactivate(struct intel_th_device *thdev)
230 {
231         struct intel_th_driver *thdrv =
232                 to_intel_th_driver_or_null(thdev->dev.driver);
233
234         if (!thdrv)
235                 return;
236
237         if (thdrv->deactivate)
238                 thdrv->deactivate(thdev);
239         else
240                 intel_th_trace_disable(thdev);
241
242         pm_runtime_put(&thdev->dev);
243         module_put(thdrv->driver.owner);
244 }
245
246 static ssize_t active_show(struct device *dev, struct device_attribute *attr,
247                            char *buf)
248 {
249         struct intel_th_device *thdev = to_intel_th_device(dev);
250
251         return scnprintf(buf, PAGE_SIZE, "%d\n", thdev->output.active);
252 }
253
254 static ssize_t active_store(struct device *dev, struct device_attribute *attr,
255                             const char *buf, size_t size)
256 {
257         struct intel_th_device *thdev = to_intel_th_device(dev);
258         unsigned long val;
259         int ret;
260
261         ret = kstrtoul(buf, 10, &val);
262         if (ret)
263                 return ret;
264
265         if (!!val != thdev->output.active) {
266                 if (val)
267                         ret = intel_th_output_activate(thdev);
268                 else
269                         intel_th_output_deactivate(thdev);
270         }
271
272         return ret ? ret : size;
273 }
274
275 static DEVICE_ATTR_RW(active);
276
277 static struct attribute *intel_th_output_attrs[] = {
278         &dev_attr_port.attr,
279         &dev_attr_active.attr,
280         NULL,
281 };
282
283 ATTRIBUTE_GROUPS(intel_th_output);
284
285 static struct device_type intel_th_output_device_type = {
286         .name           = "intel_th_output_device",
287         .groups         = intel_th_output_groups,
288         .release        = intel_th_device_release,
289         .devnode        = intel_th_output_devnode,
290 };
291
292 static struct device_type intel_th_switch_device_type = {
293         .name           = "intel_th_switch_device",
294         .release        = intel_th_device_release,
295 };
296
297 static struct device_type *intel_th_device_type[] = {
298         [INTEL_TH_SOURCE]       = &intel_th_source_device_type,
299         [INTEL_TH_OUTPUT]       = &intel_th_output_device_type,
300         [INTEL_TH_SWITCH]       = &intel_th_switch_device_type,
301 };
302
303 int intel_th_driver_register(struct intel_th_driver *thdrv)
304 {
305         if (!thdrv->probe || !thdrv->remove)
306                 return -EINVAL;
307
308         thdrv->driver.bus = &intel_th_bus;
309
310         return driver_register(&thdrv->driver);
311 }
312 EXPORT_SYMBOL_GPL(intel_th_driver_register);
313
314 void intel_th_driver_unregister(struct intel_th_driver *thdrv)
315 {
316         driver_unregister(&thdrv->driver);
317 }
318 EXPORT_SYMBOL_GPL(intel_th_driver_unregister);
319
320 static struct intel_th_device *
321 intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name,
322                       int id)
323 {
324         struct device *parent;
325         struct intel_th_device *thdev;
326
327         if (type == INTEL_TH_SWITCH)
328                 parent = th->dev;
329         else
330                 parent = &th->hub->dev;
331
332         thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL);
333         if (!thdev)
334                 return NULL;
335
336         thdev->id = id;
337         thdev->type = type;
338
339         strcpy(thdev->name, name);
340         device_initialize(&thdev->dev);
341         thdev->dev.bus = &intel_th_bus;
342         thdev->dev.type = intel_th_device_type[type];
343         thdev->dev.parent = parent;
344         thdev->dev.dma_mask = parent->dma_mask;
345         thdev->dev.dma_parms = parent->dma_parms;
346         dma_set_coherent_mask(&thdev->dev, parent->coherent_dma_mask);
347         if (id >= 0)
348                 dev_set_name(&thdev->dev, "%d-%s%d", th->id, name, id);
349         else
350                 dev_set_name(&thdev->dev, "%d-%s", th->id, name);
351
352         return thdev;
353 }
354
355 static int intel_th_device_add_resources(struct intel_th_device *thdev,
356                                          struct resource *res, int nres)
357 {
358         struct resource *r;
359
360         r = kmemdup(res, sizeof(*res) * nres, GFP_KERNEL);
361         if (!r)
362                 return -ENOMEM;
363
364         thdev->resource = r;
365         thdev->num_resources = nres;
366
367         return 0;
368 }
369
370 static void intel_th_device_remove(struct intel_th_device *thdev)
371 {
372         device_del(&thdev->dev);
373         put_device(&thdev->dev);
374 }
375
376 static void intel_th_device_free(struct intel_th_device *thdev)
377 {
378         kfree(thdev->resource);
379         kfree(thdev);
380 }
381
382 /*
383  * Intel(R) Trace Hub subdevices
384  */
385 static struct intel_th_subdevice {
386         const char              *name;
387         struct resource         res[3];
388         unsigned                nres;
389         unsigned                type;
390         unsigned                otype;
391         unsigned                scrpd;
392         int                     id;
393 } intel_th_subdevices[TH_SUBDEVICE_MAX] = {
394         {
395                 .nres   = 1,
396                 .res    = {
397                         {
398                                 .start  = REG_GTH_OFFSET,
399                                 .end    = REG_GTH_OFFSET + REG_GTH_LENGTH - 1,
400                                 .flags  = IORESOURCE_MEM,
401                         },
402                 },
403                 .name   = "gth",
404                 .type   = INTEL_TH_SWITCH,
405                 .id     = -1,
406         },
407         {
408                 .nres   = 2,
409                 .res    = {
410                         {
411                                 .start  = REG_MSU_OFFSET,
412                                 .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
413                                 .flags  = IORESOURCE_MEM,
414                         },
415                         {
416                                 .start  = BUF_MSU_OFFSET,
417                                 .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
418                                 .flags  = IORESOURCE_MEM,
419                         },
420                 },
421                 .name   = "msc",
422                 .id     = 0,
423                 .type   = INTEL_TH_OUTPUT,
424                 .otype  = GTH_MSU,
425                 .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
426         },
427         {
428                 .nres   = 2,
429                 .res    = {
430                         {
431                                 .start  = REG_MSU_OFFSET,
432                                 .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
433                                 .flags  = IORESOURCE_MEM,
434                         },
435                         {
436                                 .start  = BUF_MSU_OFFSET,
437                                 .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
438                                 .flags  = IORESOURCE_MEM,
439                         },
440                 },
441                 .name   = "msc",
442                 .id     = 1,
443                 .type   = INTEL_TH_OUTPUT,
444                 .otype  = GTH_MSU,
445                 .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
446         },
447         {
448                 .nres   = 2,
449                 .res    = {
450                         {
451                                 .start  = REG_STH_OFFSET,
452                                 .end    = REG_STH_OFFSET + REG_STH_LENGTH - 1,
453                                 .flags  = IORESOURCE_MEM,
454                         },
455                         {
456                                 .start  = TH_MMIO_SW,
457                                 .end    = 0,
458                                 .flags  = IORESOURCE_MEM,
459                         },
460                 },
461                 .id     = -1,
462                 .name   = "sth",
463                 .type   = INTEL_TH_SOURCE,
464         },
465         {
466                 .nres   = 1,
467                 .res    = {
468                         {
469                                 .start  = REG_PTI_OFFSET,
470                                 .end    = REG_PTI_OFFSET + REG_PTI_LENGTH - 1,
471                                 .flags  = IORESOURCE_MEM,
472                         },
473                 },
474                 .id     = -1,
475                 .name   = "pti",
476                 .type   = INTEL_TH_OUTPUT,
477                 .otype  = GTH_PTI,
478                 .scrpd  = SCRPD_PTI_IS_PRIM_DEST,
479         },
480         {
481                 .nres   = 1,
482                 .res    = {
483                         {
484                                 .start  = REG_DCIH_OFFSET,
485                                 .end    = REG_DCIH_OFFSET + REG_DCIH_LENGTH - 1,
486                                 .flags  = IORESOURCE_MEM,
487                         },
488                 },
489                 .id     = -1,
490                 .name   = "dcih",
491                 .type   = INTEL_TH_OUTPUT,
492         },
493 };
494
495 #ifdef CONFIG_MODULES
496 static void __intel_th_request_hub_module(struct work_struct *work)
497 {
498         struct intel_th *th = container_of(work, struct intel_th,
499                                            request_module_work);
500
501         request_module("intel_th_%s", th->hub->name);
502 }
503
504 static int intel_th_request_hub_module(struct intel_th *th)
505 {
506         INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
507         schedule_work(&th->request_module_work);
508
509         return 0;
510 }
511
512 static void intel_th_request_hub_module_flush(struct intel_th *th)
513 {
514         flush_work(&th->request_module_work);
515 }
516 #else
517 static inline int intel_th_request_hub_module(struct intel_th *th)
518 {
519         return -EINVAL;
520 }
521
522 static inline void intel_th_request_hub_module_flush(struct intel_th *th)
523 {
524 }
525 #endif /* CONFIG_MODULES */
526
527 static int intel_th_populate(struct intel_th *th, struct resource *devres,
528                              unsigned int ndevres, int irq)
529 {
530         struct resource res[3];
531         unsigned int req = 0;
532         int i, err;
533
534         /* create devices for each intel_th_subdevice */
535         for (i = 0; i < ARRAY_SIZE(intel_th_subdevices); i++) {
536                 struct intel_th_subdevice *subdev = &intel_th_subdevices[i];
537                 struct intel_th_device *thdev;
538                 int r;
539
540                 thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
541                                               subdev->id);
542                 if (!thdev) {
543                         err = -ENOMEM;
544                         goto kill_subdevs;
545                 }
546
547                 memcpy(res, subdev->res,
548                        sizeof(struct resource) * subdev->nres);
549
550                 for (r = 0; r < subdev->nres; r++) {
551                         int bar = TH_MMIO_CONFIG;
552
553                         /*
554                          * Take .end == 0 to mean 'take the whole bar',
555                          * .start then tells us which bar it is. Default to
556                          * TH_MMIO_CONFIG.
557                          */
558                         if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
559                                 bar = res[r].start;
560                                 res[r].start = 0;
561                                 res[r].end = resource_size(&devres[bar]) - 1;
562                         }
563
564                         if (res[r].flags & IORESOURCE_MEM) {
565                                 res[r].start    += devres[bar].start;
566                                 res[r].end      += devres[bar].start;
567
568                                 dev_dbg(th->dev, "%s:%d @ %pR\n",
569                                         subdev->name, r, &res[r]);
570                         } else if (res[r].flags & IORESOURCE_IRQ) {
571                                 res[r].start    = irq;
572                         }
573                 }
574
575                 err = intel_th_device_add_resources(thdev, res, subdev->nres);
576                 if (err) {
577                         put_device(&thdev->dev);
578                         goto kill_subdevs;
579                 }
580
581                 if (subdev->type == INTEL_TH_OUTPUT) {
582                         thdev->dev.devt = MKDEV(th->major, i);
583                         thdev->output.type = subdev->otype;
584                         thdev->output.port = -1;
585                         thdev->output.scratchpad = subdev->scrpd;
586                 }
587
588                 err = device_add(&thdev->dev);
589                 if (err) {
590                         put_device(&thdev->dev);
591                         goto kill_subdevs;
592                 }
593
594                 /* need switch driver to be loaded to enumerate the rest */
595                 if (subdev->type == INTEL_TH_SWITCH && !req) {
596                         th->hub = thdev;
597                         err = intel_th_request_hub_module(th);
598                         if (!err)
599                                 req++;
600                 }
601
602                 th->thdev[i] = thdev;
603         }
604
605         return 0;
606
607 kill_subdevs:
608         for (i-- ; i >= 0; i--)
609                 intel_th_device_remove(th->thdev[i]);
610
611         return err;
612 }
613
614 static int match_devt(struct device *dev, void *data)
615 {
616         dev_t devt = (dev_t)(unsigned long)data;
617
618         return dev->devt == devt;
619 }
620
621 static int intel_th_output_open(struct inode *inode, struct file *file)
622 {
623         const struct file_operations *fops;
624         struct intel_th_driver *thdrv;
625         struct device *dev;
626         int err;
627
628         dev = bus_find_device(&intel_th_bus, NULL,
629                               (void *)(unsigned long)inode->i_rdev,
630                               match_devt);
631         if (!dev || !dev->driver)
632                 return -ENODEV;
633
634         thdrv = to_intel_th_driver(dev->driver);
635         fops = fops_get(thdrv->fops);
636         if (!fops)
637                 return -ENODEV;
638
639         replace_fops(file, fops);
640
641         file->private_data = to_intel_th_device(dev);
642
643         if (file->f_op->open) {
644                 err = file->f_op->open(inode, file);
645                 return err;
646         }
647
648         return 0;
649 }
650
651 static const struct file_operations intel_th_output_fops = {
652         .open   = intel_th_output_open,
653         .llseek = noop_llseek,
654 };
655
656 /**
657  * intel_th_alloc() - allocate a new Intel TH device and its subdevices
658  * @dev:        parent device
659  * @devres:     parent's resources
660  * @ndevres:    number of resources
661  * @irq:        irq number
662  */
663 struct intel_th *
664 intel_th_alloc(struct device *dev, struct resource *devres,
665                unsigned int ndevres, int irq)
666 {
667         struct intel_th *th;
668         int err;
669
670         th = kzalloc(sizeof(*th), GFP_KERNEL);
671         if (!th)
672                 return ERR_PTR(-ENOMEM);
673
674         th->id = ida_simple_get(&intel_th_ida, 0, 0, GFP_KERNEL);
675         if (th->id < 0) {
676                 err = th->id;
677                 goto err_alloc;
678         }
679
680         th->major = __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS,
681                                       "intel_th/output", &intel_th_output_fops);
682         if (th->major < 0) {
683                 err = th->major;
684                 goto err_ida;
685         }
686         th->dev = dev;
687
688         dev_set_drvdata(dev, th);
689
690         pm_runtime_no_callbacks(dev);
691         pm_runtime_put(dev);
692         pm_runtime_allow(dev);
693
694         err = intel_th_populate(th, devres, ndevres, irq);
695         if (err)
696                 goto err_chrdev;
697
698         return th;
699
700 err_chrdev:
701         pm_runtime_forbid(dev);
702
703         __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
704                             "intel_th/output");
705
706 err_ida:
707         ida_simple_remove(&intel_th_ida, th->id);
708
709 err_alloc:
710         kfree(th);
711
712         return ERR_PTR(err);
713 }
714 EXPORT_SYMBOL_GPL(intel_th_alloc);
715
716 void intel_th_free(struct intel_th *th)
717 {
718         int i;
719
720         intel_th_request_hub_module_flush(th);
721         for (i = 0; i < TH_SUBDEVICE_MAX; i++)
722                 if (th->thdev[i] != th->hub)
723                         intel_th_device_remove(th->thdev[i]);
724
725         intel_th_device_remove(th->hub);
726
727         pm_runtime_get_sync(th->dev);
728         pm_runtime_forbid(th->dev);
729
730         __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
731                             "intel_th/output");
732
733         ida_simple_remove(&intel_th_ida, th->id);
734
735         kfree(th);
736 }
737 EXPORT_SYMBOL_GPL(intel_th_free);
738
739 /**
740  * intel_th_trace_enable() - enable tracing for an output device
741  * @thdev:      output device that requests tracing be enabled
742  */
743 int intel_th_trace_enable(struct intel_th_device *thdev)
744 {
745         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
746         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
747
748         if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
749                 return -EINVAL;
750
751         if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
752                 return -EINVAL;
753
754         pm_runtime_get_sync(&thdev->dev);
755         hubdrv->enable(hub, &thdev->output);
756
757         return 0;
758 }
759 EXPORT_SYMBOL_GPL(intel_th_trace_enable);
760
761 /**
762  * intel_th_trace_disable() - disable tracing for an output device
763  * @thdev:      output device that requests tracing be disabled
764  */
765 int intel_th_trace_disable(struct intel_th_device *thdev)
766 {
767         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
768         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
769
770         WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH);
771         if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
772                 return -EINVAL;
773
774         hubdrv->disable(hub, &thdev->output);
775         pm_runtime_put(&thdev->dev);
776
777         return 0;
778 }
779 EXPORT_SYMBOL_GPL(intel_th_trace_disable);
780
781 int intel_th_set_output(struct intel_th_device *thdev,
782                         unsigned int master)
783 {
784         struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
785         struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
786
787         if (!hubdrv->set_output)
788                 return -ENOTSUPP;
789
790         return hubdrv->set_output(hub, master);
791 }
792 EXPORT_SYMBOL_GPL(intel_th_set_output);
793
794 static int __init intel_th_init(void)
795 {
796         intel_th_debug_init();
797
798         return bus_register(&intel_th_bus);
799 }
800 subsys_initcall(intel_th_init);
801
802 static void __exit intel_th_exit(void)
803 {
804         intel_th_debug_done();
805
806         bus_unregister(&intel_th_bus);
807 }
808 module_exit(intel_th_exit);
809
810 MODULE_LICENSE("GPL v2");
811 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
812 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");