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