2 * Intel(R) Trace Hub driver core
4 * Copyright (C) 2014-2015 Intel Corporation.
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.
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
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
32 static bool host_mode __read_mostly
;
33 module_param(host_mode
, bool, 0444);
35 static DEFINE_IDA(intel_th_ida
);
37 static int intel_th_match(struct device
*dev
, struct device_driver
*driver
)
39 struct intel_th_driver
*thdrv
= to_intel_th_driver(driver
);
40 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
42 if (thdev
->type
== INTEL_TH_SWITCH
&&
43 (!thdrv
->enable
|| !thdrv
->disable
))
46 return !strcmp(thdev
->name
, driver
->name
);
49 static int intel_th_child_remove(struct device
*dev
, void *data
)
51 device_release_driver(dev
);
56 static int intel_th_probe(struct device
*dev
)
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
;
64 if (thdev
->type
== INTEL_TH_SWITCH
)
67 hub
= to_intel_th_device(dev
->parent
);
69 if (!hub
|| !hub
->dev
.driver
)
72 hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
74 pm_runtime_set_active(dev
);
75 pm_runtime_no_callbacks(dev
);
76 pm_runtime_enable(dev
);
78 ret
= thdrv
->probe(to_intel_th_device(dev
));
82 if (thdrv
->attr_group
) {
83 ret
= sysfs_create_group(&thdev
->dev
.kobj
, thdrv
->attr_group
);
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
);
99 pm_runtime_disable(dev
);
104 static void intel_th_device_remove(struct intel_th_device
*thdev
);
106 static int intel_th_remove(struct device
*dev
)
108 struct intel_th_driver
*thdrv
= to_intel_th_driver(dev
->driver
);
109 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
110 struct intel_th_device
*hub
= to_intel_th_hub(thdev
);
113 if (thdev
->type
== INTEL_TH_SWITCH
) {
114 struct intel_th
*th
= to_intel_th(hub
);
117 /* disconnect outputs */
118 err
= device_for_each_child(dev
, thdev
, intel_th_child_remove
);
123 * Remove outputs, that is, hub's children: they are created
124 * at hub's probe time by having the hub call
125 * intel_th_output_enable() for each of them.
127 for (i
= 0, lowest
= -1; i
< th
->num_thdevs
; i
++) {
129 * Move the non-output devices from higher up the
130 * th->thdev[] array to lower positions to maintain
131 * a contiguous array.
133 if (th
->thdev
[i
]->type
!= INTEL_TH_OUTPUT
) {
135 th
->thdev
[lowest
] = th
->thdev
[i
];
146 intel_th_device_remove(th
->thdev
[i
]);
150 th
->num_thdevs
= lowest
;
153 if (thdrv
->attr_group
)
154 sysfs_remove_group(&thdev
->dev
.kobj
, thdrv
->attr_group
);
156 pm_runtime_get_sync(dev
);
158 thdrv
->remove(thdev
);
160 if (intel_th_output_assigned(thdev
)) {
161 struct intel_th_driver
*hubdrv
=
162 to_intel_th_driver(dev
->parent
->driver
);
165 /* does not talk to hardware */
166 hubdrv
->unassign(hub
, thdev
);
169 pm_runtime_disable(dev
);
170 pm_runtime_set_active(dev
);
171 pm_runtime_enable(dev
);
176 static struct bus_type intel_th_bus
= {
178 .match
= intel_th_match
,
179 .probe
= intel_th_probe
,
180 .remove
= intel_th_remove
,
183 static void intel_th_device_free(struct intel_th_device
*thdev
);
185 static void intel_th_device_release(struct device
*dev
)
187 intel_th_device_free(to_intel_th_device(dev
));
190 static struct device_type intel_th_source_device_type
= {
191 .name
= "intel_th_source_device",
192 .release
= intel_th_device_release
,
195 static char *intel_th_output_devnode(struct device
*dev
, umode_t
*mode
,
196 kuid_t
*uid
, kgid_t
*gid
)
198 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
199 struct intel_th
*th
= to_intel_th(thdev
);
203 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s%d", th
->id
,
204 thdev
->name
, thdev
->id
);
206 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s", th
->id
,
212 static ssize_t
port_show(struct device
*dev
, struct device_attribute
*attr
,
215 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
217 if (thdev
->output
.port
>= 0)
218 return scnprintf(buf
, PAGE_SIZE
, "%u\n", thdev
->output
.port
);
220 return scnprintf(buf
, PAGE_SIZE
, "unassigned\n");
223 static DEVICE_ATTR_RO(port
);
225 static int intel_th_output_activate(struct intel_th_device
*thdev
)
227 struct intel_th_driver
*thdrv
=
228 to_intel_th_driver_or_null(thdev
->dev
.driver
);
229 struct intel_th
*th
= to_intel_th(thdev
);
235 if (!try_module_get(thdrv
->driver
.owner
))
238 pm_runtime_get_sync(&thdev
->dev
);
241 ret
= th
->activate(th
);
246 ret
= thdrv
->activate(thdev
);
248 intel_th_trace_enable(thdev
);
251 goto fail_deactivate
;
260 pm_runtime_put(&thdev
->dev
);
261 module_put(thdrv
->driver
.owner
);
266 static void intel_th_output_deactivate(struct intel_th_device
*thdev
)
268 struct intel_th_driver
*thdrv
=
269 to_intel_th_driver_or_null(thdev
->dev
.driver
);
270 struct intel_th
*th
= to_intel_th(thdev
);
275 if (thdrv
->deactivate
)
276 thdrv
->deactivate(thdev
);
278 intel_th_trace_disable(thdev
);
283 pm_runtime_put(&thdev
->dev
);
284 module_put(thdrv
->driver
.owner
);
287 static ssize_t
active_show(struct device
*dev
, struct device_attribute
*attr
,
290 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
292 return scnprintf(buf
, PAGE_SIZE
, "%d\n", thdev
->output
.active
);
295 static ssize_t
active_store(struct device
*dev
, struct device_attribute
*attr
,
296 const char *buf
, size_t size
)
298 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
302 ret
= kstrtoul(buf
, 10, &val
);
306 if (!!val
!= thdev
->output
.active
) {
308 ret
= intel_th_output_activate(thdev
);
310 intel_th_output_deactivate(thdev
);
313 return ret
? ret
: size
;
316 static DEVICE_ATTR_RW(active
);
318 static struct attribute
*intel_th_output_attrs
[] = {
320 &dev_attr_active
.attr
,
324 ATTRIBUTE_GROUPS(intel_th_output
);
326 static struct device_type intel_th_output_device_type
= {
327 .name
= "intel_th_output_device",
328 .groups
= intel_th_output_groups
,
329 .release
= intel_th_device_release
,
330 .devnode
= intel_th_output_devnode
,
333 static struct device_type intel_th_switch_device_type
= {
334 .name
= "intel_th_switch_device",
335 .release
= intel_th_device_release
,
338 static struct device_type
*intel_th_device_type
[] = {
339 [INTEL_TH_SOURCE
] = &intel_th_source_device_type
,
340 [INTEL_TH_OUTPUT
] = &intel_th_output_device_type
,
341 [INTEL_TH_SWITCH
] = &intel_th_switch_device_type
,
344 int intel_th_driver_register(struct intel_th_driver
*thdrv
)
346 if (!thdrv
->probe
|| !thdrv
->remove
)
349 thdrv
->driver
.bus
= &intel_th_bus
;
351 return driver_register(&thdrv
->driver
);
353 EXPORT_SYMBOL_GPL(intel_th_driver_register
);
355 void intel_th_driver_unregister(struct intel_th_driver
*thdrv
)
357 driver_unregister(&thdrv
->driver
);
359 EXPORT_SYMBOL_GPL(intel_th_driver_unregister
);
361 static struct intel_th_device
*
362 intel_th_device_alloc(struct intel_th
*th
, unsigned int type
, const char *name
,
365 struct device
*parent
;
366 struct intel_th_device
*thdev
;
368 if (type
== INTEL_TH_OUTPUT
)
369 parent
= &th
->hub
->dev
;
373 thdev
= kzalloc(sizeof(*thdev
) + strlen(name
) + 1, GFP_KERNEL
);
380 strcpy(thdev
->name
, name
);
381 device_initialize(&thdev
->dev
);
382 thdev
->dev
.bus
= &intel_th_bus
;
383 thdev
->dev
.type
= intel_th_device_type
[type
];
384 thdev
->dev
.parent
= parent
;
385 thdev
->dev
.dma_mask
= parent
->dma_mask
;
386 thdev
->dev
.dma_parms
= parent
->dma_parms
;
387 dma_set_coherent_mask(&thdev
->dev
, parent
->coherent_dma_mask
);
389 dev_set_name(&thdev
->dev
, "%d-%s%d", th
->id
, name
, id
);
391 dev_set_name(&thdev
->dev
, "%d-%s", th
->id
, name
);
396 static int intel_th_device_add_resources(struct intel_th_device
*thdev
,
397 struct resource
*res
, int nres
)
401 r
= kmemdup(res
, sizeof(*res
) * nres
, GFP_KERNEL
);
406 thdev
->num_resources
= nres
;
411 static void intel_th_device_remove(struct intel_th_device
*thdev
)
413 device_del(&thdev
->dev
);
414 put_device(&thdev
->dev
);
417 static void intel_th_device_free(struct intel_th_device
*thdev
)
419 kfree(thdev
->resource
);
424 * Intel(R) Trace Hub subdevices
426 static const struct intel_th_subdevice
{
428 struct resource res
[3];
434 } intel_th_subdevices
[] = {
439 /* Handle TSCU from GTH driver */
440 .start
= REG_GTH_OFFSET
,
441 .end
= REG_TSCU_OFFSET
+ REG_TSCU_LENGTH
- 1,
442 .flags
= IORESOURCE_MEM
,
446 .type
= INTEL_TH_SWITCH
,
453 .start
= REG_MSU_OFFSET
,
454 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
455 .flags
= IORESOURCE_MEM
,
458 .start
= BUF_MSU_OFFSET
,
459 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
460 .flags
= IORESOURCE_MEM
,
465 .type
= INTEL_TH_OUTPUT
,
467 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC0_IS_ENABLED
,
473 .start
= REG_MSU_OFFSET
,
474 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
475 .flags
= IORESOURCE_MEM
,
478 .start
= BUF_MSU_OFFSET
,
479 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
480 .flags
= IORESOURCE_MEM
,
485 .type
= INTEL_TH_OUTPUT
,
487 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC1_IS_ENABLED
,
493 .start
= REG_STH_OFFSET
,
494 .end
= REG_STH_OFFSET
+ REG_STH_LENGTH
- 1,
495 .flags
= IORESOURCE_MEM
,
500 .flags
= IORESOURCE_MEM
,
505 .type
= INTEL_TH_SOURCE
,
511 .start
= REG_PTI_OFFSET
,
512 .end
= REG_PTI_OFFSET
+ REG_PTI_LENGTH
- 1,
513 .flags
= IORESOURCE_MEM
,
518 .type
= INTEL_TH_OUTPUT
,
520 .scrpd
= SCRPD_PTI_IS_PRIM_DEST
,
526 .start
= REG_PTI_OFFSET
,
527 .end
= REG_PTI_OFFSET
+ REG_PTI_LENGTH
- 1,
528 .flags
= IORESOURCE_MEM
,
533 .type
= INTEL_TH_OUTPUT
,
535 .scrpd
= SCRPD_PTI_IS_PRIM_DEST
,
541 .start
= REG_DCIH_OFFSET
,
542 .end
= REG_DCIH_OFFSET
+ REG_DCIH_LENGTH
- 1,
543 .flags
= IORESOURCE_MEM
,
548 .type
= INTEL_TH_OUTPUT
,
552 #ifdef CONFIG_MODULES
553 static void __intel_th_request_hub_module(struct work_struct
*work
)
555 struct intel_th
*th
= container_of(work
, struct intel_th
,
556 request_module_work
);
558 request_module("intel_th_%s", th
->hub
->name
);
561 static int intel_th_request_hub_module(struct intel_th
*th
)
563 INIT_WORK(&th
->request_module_work
, __intel_th_request_hub_module
);
564 schedule_work(&th
->request_module_work
);
569 static void intel_th_request_hub_module_flush(struct intel_th
*th
)
571 flush_work(&th
->request_module_work
);
574 static inline int intel_th_request_hub_module(struct intel_th
*th
)
579 static inline void intel_th_request_hub_module_flush(struct intel_th
*th
)
582 #endif /* CONFIG_MODULES */
584 static struct intel_th_device
*
585 intel_th_subdevice_alloc(struct intel_th
*th
,
586 const struct intel_th_subdevice
*subdev
)
588 struct intel_th_device
*thdev
;
589 struct resource res
[3];
590 unsigned int req
= 0;
593 thdev
= intel_th_device_alloc(th
, subdev
->type
, subdev
->name
,
596 return ERR_PTR(-ENOMEM
);
598 thdev
->drvdata
= th
->drvdata
;
600 memcpy(res
, subdev
->res
,
601 sizeof(struct resource
) * subdev
->nres
);
603 for (r
= 0; r
< subdev
->nres
; r
++) {
604 struct resource
*devres
= th
->resource
;
605 int bar
= TH_MMIO_CONFIG
;
608 * Take .end == 0 to mean 'take the whole bar',
609 * .start then tells us which bar it is. Default to
612 if (!res
[r
].end
&& res
[r
].flags
== IORESOURCE_MEM
) {
615 res
[r
].end
= resource_size(&devres
[bar
]) - 1;
618 if (res
[r
].flags
& IORESOURCE_MEM
) {
619 res
[r
].start
+= devres
[bar
].start
;
620 res
[r
].end
+= devres
[bar
].start
;
622 dev_dbg(th
->dev
, "%s:%d @ %pR\n",
623 subdev
->name
, r
, &res
[r
]);
624 } else if (res
[r
].flags
& IORESOURCE_IRQ
) {
625 res
[r
].start
= th
->irq
;
629 err
= intel_th_device_add_resources(thdev
, res
, subdev
->nres
);
631 put_device(&thdev
->dev
);
632 goto fail_put_device
;
635 if (subdev
->type
== INTEL_TH_OUTPUT
) {
636 thdev
->dev
.devt
= MKDEV(th
->major
, th
->num_thdevs
);
637 thdev
->output
.type
= subdev
->otype
;
638 thdev
->output
.port
= -1;
639 thdev
->output
.scratchpad
= subdev
->scrpd
;
640 } else if (subdev
->type
== INTEL_TH_SWITCH
) {
641 thdev
->host_mode
= host_mode
;
645 err
= device_add(&thdev
->dev
);
647 put_device(&thdev
->dev
);
651 /* need switch driver to be loaded to enumerate the rest */
652 if (subdev
->type
== INTEL_TH_SWITCH
&& !req
) {
653 err
= intel_th_request_hub_module(th
);
661 kfree(thdev
->resource
);
664 put_device(&thdev
->dev
);
670 * intel_th_output_enable() - find and enable a device for a given output type
671 * @th: Intel TH instance
672 * @otype: output type
674 * Go through the unallocated output devices, find the first one whos type
675 * matches @otype and instantiate it. These devices are removed when the hub
676 * device is removed, see intel_th_remove().
678 int intel_th_output_enable(struct intel_th
*th
, unsigned int otype
)
680 struct intel_th_device
*thdev
;
681 int src
= 0, dst
= 0;
683 for (src
= 0, dst
= 0; dst
<= th
->num_thdevs
; src
++, dst
++) {
684 for (; src
< ARRAY_SIZE(intel_th_subdevices
); src
++) {
685 if (intel_th_subdevices
[src
].type
!= INTEL_TH_OUTPUT
)
688 if (intel_th_subdevices
[src
].otype
!= otype
)
694 /* no unallocated matching subdevices */
695 if (src
== ARRAY_SIZE(intel_th_subdevices
))
698 for (; dst
< th
->num_thdevs
; dst
++) {
699 if (th
->thdev
[dst
]->type
!= INTEL_TH_OUTPUT
)
702 if (th
->thdev
[dst
]->output
.type
!= otype
)
709 * intel_th_subdevices[src] matches our requirements and is
710 * not matched in th::thdev[]
712 if (dst
== th
->num_thdevs
)
719 thdev
= intel_th_subdevice_alloc(th
, &intel_th_subdevices
[src
]);
721 return PTR_ERR(thdev
);
723 th
->thdev
[th
->num_thdevs
++] = thdev
;
727 EXPORT_SYMBOL_GPL(intel_th_output_enable
);
729 static int intel_th_populate(struct intel_th
*th
)
733 /* create devices for each intel_th_subdevice */
734 for (src
= 0; src
< ARRAY_SIZE(intel_th_subdevices
); src
++) {
735 const struct intel_th_subdevice
*subdev
=
736 &intel_th_subdevices
[src
];
737 struct intel_th_device
*thdev
;
739 /* only allow SOURCE and SWITCH devices in host mode */
740 if (host_mode
&& subdev
->type
== INTEL_TH_OUTPUT
)
744 * don't enable port OUTPUTs in this path; SWITCH enables them
745 * via intel_th_output_enable()
747 if (subdev
->type
== INTEL_TH_OUTPUT
&&
748 subdev
->otype
!= GTH_NONE
)
751 thdev
= intel_th_subdevice_alloc(th
, subdev
);
752 /* note: caller should free subdevices from th::thdev[] */
754 return PTR_ERR(thdev
);
756 th
->thdev
[th
->num_thdevs
++] = thdev
;
762 static int match_devt(struct device
*dev
, void *data
)
764 dev_t devt
= (dev_t
)(unsigned long)data
;
766 return dev
->devt
== devt
;
769 static int intel_th_output_open(struct inode
*inode
, struct file
*file
)
771 const struct file_operations
*fops
;
772 struct intel_th_driver
*thdrv
;
776 dev
= bus_find_device(&intel_th_bus
, NULL
,
777 (void *)(unsigned long)inode
->i_rdev
,
779 if (!dev
|| !dev
->driver
)
782 thdrv
= to_intel_th_driver(dev
->driver
);
783 fops
= fops_get(thdrv
->fops
);
787 replace_fops(file
, fops
);
789 file
->private_data
= to_intel_th_device(dev
);
791 if (file
->f_op
->open
) {
792 err
= file
->f_op
->open(inode
, file
);
799 static const struct file_operations intel_th_output_fops
= {
800 .open
= intel_th_output_open
,
801 .llseek
= noop_llseek
,
805 * intel_th_alloc() - allocate a new Intel TH device and its subdevices
806 * @dev: parent device
807 * @devres: parent's resources
808 * @ndevres: number of resources
812 intel_th_alloc(struct device
*dev
, struct intel_th_drvdata
*drvdata
,
813 struct resource
*devres
, unsigned int ndevres
, int irq
)
818 th
= kzalloc(sizeof(*th
), GFP_KERNEL
);
820 return ERR_PTR(-ENOMEM
);
822 th
->id
= ida_simple_get(&intel_th_ida
, 0, 0, GFP_KERNEL
);
828 th
->major
= __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS
,
829 "intel_th/output", &intel_th_output_fops
);
835 th
->drvdata
= drvdata
;
837 th
->resource
= devres
;
838 th
->num_resources
= ndevres
;
841 dev_set_drvdata(dev
, th
);
843 pm_runtime_no_callbacks(dev
);
845 pm_runtime_allow(dev
);
847 err
= intel_th_populate(th
);
849 /* free the subdevices and undo everything */
857 ida_simple_remove(&intel_th_ida
, th
->id
);
864 EXPORT_SYMBOL_GPL(intel_th_alloc
);
866 void intel_th_free(struct intel_th
*th
)
870 intel_th_request_hub_module_flush(th
);
872 intel_th_device_remove(th
->hub
);
873 for (i
= 0; i
< th
->num_thdevs
; i
++) {
874 if (th
->thdev
[i
] != th
->hub
)
875 intel_th_device_remove(th
->thdev
[i
]);
881 pm_runtime_get_sync(th
->dev
);
882 pm_runtime_forbid(th
->dev
);
884 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
887 ida_simple_remove(&intel_th_ida
, th
->id
);
891 EXPORT_SYMBOL_GPL(intel_th_free
);
894 * intel_th_trace_enable() - enable tracing for an output device
895 * @thdev: output device that requests tracing be enabled
897 int intel_th_trace_enable(struct intel_th_device
*thdev
)
899 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
900 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
902 if (WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
))
905 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
908 pm_runtime_get_sync(&thdev
->dev
);
909 hubdrv
->enable(hub
, &thdev
->output
);
913 EXPORT_SYMBOL_GPL(intel_th_trace_enable
);
916 * intel_th_trace_disable() - disable tracing for an output device
917 * @thdev: output device that requests tracing be disabled
919 int intel_th_trace_disable(struct intel_th_device
*thdev
)
921 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
922 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
924 WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
);
925 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
928 hubdrv
->disable(hub
, &thdev
->output
);
929 pm_runtime_put(&thdev
->dev
);
933 EXPORT_SYMBOL_GPL(intel_th_trace_disable
);
935 int intel_th_set_output(struct intel_th_device
*thdev
,
938 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
939 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
941 if (!hubdrv
->set_output
)
944 return hubdrv
->set_output(hub
, master
);
946 EXPORT_SYMBOL_GPL(intel_th_set_output
);
948 static int __init
intel_th_init(void)
950 intel_th_debug_init();
952 return bus_register(&intel_th_bus
);
954 subsys_initcall(intel_th_init
);
956 static void __exit
intel_th_exit(void)
958 intel_th_debug_done();
960 bus_unregister(&intel_th_bus
);
962 module_exit(intel_th_exit
);
964 MODULE_LICENSE("GPL v2");
965 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
966 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");