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 int intel_th_remove(struct device
*dev
)
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
);
111 if (thdev
->type
== INTEL_TH_SWITCH
) {
112 err
= device_for_each_child(dev
, thdev
, intel_th_child_remove
);
117 if (thdrv
->attr_group
)
118 sysfs_remove_group(&thdev
->dev
.kobj
, thdrv
->attr_group
);
120 pm_runtime_get_sync(dev
);
122 thdrv
->remove(thdev
);
124 if (intel_th_output_assigned(thdev
)) {
125 struct intel_th_driver
*hubdrv
=
126 to_intel_th_driver(dev
->parent
->driver
);
129 /* does not talk to hardware */
130 hubdrv
->unassign(hub
, thdev
);
133 pm_runtime_disable(dev
);
134 pm_runtime_set_active(dev
);
135 pm_runtime_enable(dev
);
140 static struct bus_type intel_th_bus
= {
143 .match
= intel_th_match
,
144 .probe
= intel_th_probe
,
145 .remove
= intel_th_remove
,
148 static void intel_th_device_free(struct intel_th_device
*thdev
);
150 static void intel_th_device_release(struct device
*dev
)
152 intel_th_device_free(to_intel_th_device(dev
));
155 static struct device_type intel_th_source_device_type
= {
156 .name
= "intel_th_source_device",
157 .release
= intel_th_device_release
,
160 static struct intel_th
*to_intel_th(struct intel_th_device
*thdev
)
163 * subdevice tree is flat: if this one is not a switch, its
166 if (thdev
->type
!= INTEL_TH_SWITCH
)
167 thdev
= to_intel_th_hub(thdev
);
169 if (WARN_ON_ONCE(!thdev
|| thdev
->type
!= INTEL_TH_SWITCH
))
172 return dev_get_drvdata(thdev
->dev
.parent
);
175 static char *intel_th_output_devnode(struct device
*dev
, umode_t
*mode
,
176 kuid_t
*uid
, kgid_t
*gid
)
178 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
179 struct intel_th
*th
= to_intel_th(thdev
);
183 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s%d", th
->id
,
184 thdev
->name
, thdev
->id
);
186 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s", th
->id
,
192 static ssize_t
port_show(struct device
*dev
, struct device_attribute
*attr
,
195 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
197 if (thdev
->output
.port
>= 0)
198 return scnprintf(buf
, PAGE_SIZE
, "%u\n", thdev
->output
.port
);
200 return scnprintf(buf
, PAGE_SIZE
, "unassigned\n");
203 static DEVICE_ATTR_RO(port
);
205 static int intel_th_output_activate(struct intel_th_device
*thdev
)
207 struct intel_th_driver
*thdrv
=
208 to_intel_th_driver_or_null(thdev
->dev
.driver
);
214 if (!try_module_get(thdrv
->driver
.owner
))
217 pm_runtime_get_sync(&thdev
->dev
);
220 ret
= thdrv
->activate(thdev
);
222 intel_th_trace_enable(thdev
);
225 pm_runtime_put(&thdev
->dev
);
230 static void intel_th_output_deactivate(struct intel_th_device
*thdev
)
232 struct intel_th_driver
*thdrv
=
233 to_intel_th_driver_or_null(thdev
->dev
.driver
);
238 if (thdrv
->deactivate
)
239 thdrv
->deactivate(thdev
);
241 intel_th_trace_disable(thdev
);
243 pm_runtime_put(&thdev
->dev
);
244 module_put(thdrv
->driver
.owner
);
247 static ssize_t
active_show(struct device
*dev
, struct device_attribute
*attr
,
250 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
252 return scnprintf(buf
, PAGE_SIZE
, "%d\n", thdev
->output
.active
);
255 static ssize_t
active_store(struct device
*dev
, struct device_attribute
*attr
,
256 const char *buf
, size_t size
)
258 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
262 ret
= kstrtoul(buf
, 10, &val
);
266 if (!!val
!= thdev
->output
.active
) {
268 ret
= intel_th_output_activate(thdev
);
270 intel_th_output_deactivate(thdev
);
273 return ret
? ret
: size
;
276 static DEVICE_ATTR_RW(active
);
278 static struct attribute
*intel_th_output_attrs
[] = {
280 &dev_attr_active
.attr
,
284 ATTRIBUTE_GROUPS(intel_th_output
);
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
,
293 static struct device_type intel_th_switch_device_type
= {
294 .name
= "intel_th_switch_device",
295 .release
= intel_th_device_release
,
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
,
304 int intel_th_driver_register(struct intel_th_driver
*thdrv
)
306 if (!thdrv
->probe
|| !thdrv
->remove
)
309 thdrv
->driver
.bus
= &intel_th_bus
;
311 return driver_register(&thdrv
->driver
);
313 EXPORT_SYMBOL_GPL(intel_th_driver_register
);
315 void intel_th_driver_unregister(struct intel_th_driver
*thdrv
)
317 driver_unregister(&thdrv
->driver
);
319 EXPORT_SYMBOL_GPL(intel_th_driver_unregister
);
321 static struct intel_th_device
*
322 intel_th_device_alloc(struct intel_th
*th
, unsigned int type
, const char *name
,
325 struct device
*parent
;
326 struct intel_th_device
*thdev
;
328 if (type
== INTEL_TH_SWITCH
)
331 parent
= &th
->hub
->dev
;
333 thdev
= kzalloc(sizeof(*thdev
) + strlen(name
) + 1, GFP_KERNEL
);
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
);
349 dev_set_name(&thdev
->dev
, "%d-%s%d", th
->id
, name
, id
);
351 dev_set_name(&thdev
->dev
, "%d-%s", th
->id
, name
);
356 static int intel_th_device_add_resources(struct intel_th_device
*thdev
,
357 struct resource
*res
, int nres
)
361 r
= kmemdup(res
, sizeof(*res
) * nres
, GFP_KERNEL
);
366 thdev
->num_resources
= nres
;
371 static void intel_th_device_remove(struct intel_th_device
*thdev
)
373 device_del(&thdev
->dev
);
374 put_device(&thdev
->dev
);
377 static void intel_th_device_free(struct intel_th_device
*thdev
)
379 kfree(thdev
->resource
);
384 * Intel(R) Trace Hub subdevices
386 static const struct intel_th_subdevice
{
388 struct resource res
[3];
394 } intel_th_subdevices
[TH_SUBDEVICE_MAX
] = {
399 .start
= REG_GTH_OFFSET
,
400 .end
= REG_GTH_OFFSET
+ REG_GTH_LENGTH
- 1,
401 .flags
= IORESOURCE_MEM
,
405 .type
= INTEL_TH_SWITCH
,
412 .start
= REG_MSU_OFFSET
,
413 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
414 .flags
= IORESOURCE_MEM
,
417 .start
= BUF_MSU_OFFSET
,
418 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
419 .flags
= IORESOURCE_MEM
,
424 .type
= INTEL_TH_OUTPUT
,
426 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC0_IS_ENABLED
,
432 .start
= REG_MSU_OFFSET
,
433 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
434 .flags
= IORESOURCE_MEM
,
437 .start
= BUF_MSU_OFFSET
,
438 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
439 .flags
= IORESOURCE_MEM
,
444 .type
= INTEL_TH_OUTPUT
,
446 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC1_IS_ENABLED
,
452 .start
= REG_STH_OFFSET
,
453 .end
= REG_STH_OFFSET
+ REG_STH_LENGTH
- 1,
454 .flags
= IORESOURCE_MEM
,
459 .flags
= IORESOURCE_MEM
,
464 .type
= INTEL_TH_SOURCE
,
470 .start
= REG_PTI_OFFSET
,
471 .end
= REG_PTI_OFFSET
+ REG_PTI_LENGTH
- 1,
472 .flags
= IORESOURCE_MEM
,
477 .type
= INTEL_TH_OUTPUT
,
479 .scrpd
= SCRPD_PTI_IS_PRIM_DEST
,
485 .start
= REG_DCIH_OFFSET
,
486 .end
= REG_DCIH_OFFSET
+ REG_DCIH_LENGTH
- 1,
487 .flags
= IORESOURCE_MEM
,
492 .type
= INTEL_TH_OUTPUT
,
496 #ifdef CONFIG_MODULES
497 static void __intel_th_request_hub_module(struct work_struct
*work
)
499 struct intel_th
*th
= container_of(work
, struct intel_th
,
500 request_module_work
);
502 request_module("intel_th_%s", th
->hub
->name
);
505 static int intel_th_request_hub_module(struct intel_th
*th
)
507 INIT_WORK(&th
->request_module_work
, __intel_th_request_hub_module
);
508 schedule_work(&th
->request_module_work
);
513 static void intel_th_request_hub_module_flush(struct intel_th
*th
)
515 flush_work(&th
->request_module_work
);
518 static inline int intel_th_request_hub_module(struct intel_th
*th
)
523 static inline void intel_th_request_hub_module_flush(struct intel_th
*th
)
526 #endif /* CONFIG_MODULES */
528 static int intel_th_populate(struct intel_th
*th
, struct resource
*devres
,
529 unsigned int ndevres
, int irq
)
531 struct resource res
[3];
532 unsigned int req
= 0;
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
;
542 /* only allow SOURCE and SWITCH devices in host mode */
543 if (host_mode
&& subdev
->type
== INTEL_TH_OUTPUT
)
546 thdev
= intel_th_device_alloc(th
, subdev
->type
, subdev
->name
,
553 memcpy(res
, subdev
->res
,
554 sizeof(struct resource
) * subdev
->nres
);
556 for (r
= 0; r
< subdev
->nres
; r
++) {
557 int bar
= TH_MMIO_CONFIG
;
560 * Take .end == 0 to mean 'take the whole bar',
561 * .start then tells us which bar it is. Default to
564 if (!res
[r
].end
&& res
[r
].flags
== IORESOURCE_MEM
) {
567 res
[r
].end
= resource_size(&devres
[bar
]) - 1;
570 if (res
[r
].flags
& IORESOURCE_MEM
) {
571 res
[r
].start
+= devres
[bar
].start
;
572 res
[r
].end
+= devres
[bar
].start
;
574 dev_dbg(th
->dev
, "%s:%d @ %pR\n",
575 subdev
->name
, r
, &res
[r
]);
576 } else if (res
[r
].flags
& IORESOURCE_IRQ
) {
581 err
= intel_th_device_add_resources(thdev
, res
, subdev
->nres
);
583 put_device(&thdev
->dev
);
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
;
596 err
= device_add(&thdev
->dev
);
598 put_device(&thdev
->dev
);
602 /* need switch driver to be loaded to enumerate the rest */
603 if (subdev
->type
== INTEL_TH_SWITCH
&& !req
) {
605 err
= intel_th_request_hub_module(th
);
610 th
->thdev
[dst
++] = thdev
;
616 for (; dst
>= 0; dst
--)
617 intel_th_device_remove(th
->thdev
[dst
]);
622 static int match_devt(struct device
*dev
, void *data
)
624 dev_t devt
= (dev_t
)(unsigned long)data
;
626 return dev
->devt
== devt
;
629 static int intel_th_output_open(struct inode
*inode
, struct file
*file
)
631 const struct file_operations
*fops
;
632 struct intel_th_driver
*thdrv
;
636 dev
= bus_find_device(&intel_th_bus
, NULL
,
637 (void *)(unsigned long)inode
->i_rdev
,
639 if (!dev
|| !dev
->driver
)
642 thdrv
= to_intel_th_driver(dev
->driver
);
643 fops
= fops_get(thdrv
->fops
);
647 replace_fops(file
, fops
);
649 file
->private_data
= to_intel_th_device(dev
);
651 if (file
->f_op
->open
) {
652 err
= file
->f_op
->open(inode
, file
);
659 static const struct file_operations intel_th_output_fops
= {
660 .open
= intel_th_output_open
,
661 .llseek
= noop_llseek
,
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
672 intel_th_alloc(struct device
*dev
, struct resource
*devres
,
673 unsigned int ndevres
, int irq
)
678 th
= kzalloc(sizeof(*th
), GFP_KERNEL
);
680 return ERR_PTR(-ENOMEM
);
682 th
->id
= ida_simple_get(&intel_th_ida
, 0, 0, GFP_KERNEL
);
688 th
->major
= __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS
,
689 "intel_th/output", &intel_th_output_fops
);
696 dev_set_drvdata(dev
, th
);
698 pm_runtime_no_callbacks(dev
);
700 pm_runtime_allow(dev
);
702 err
= intel_th_populate(th
, devres
, ndevres
, irq
);
709 pm_runtime_forbid(dev
);
711 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
715 ida_simple_remove(&intel_th_ida
, th
->id
);
722 EXPORT_SYMBOL_GPL(intel_th_alloc
);
724 void intel_th_free(struct intel_th
*th
)
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
]);
733 intel_th_device_remove(th
->hub
);
735 pm_runtime_get_sync(th
->dev
);
736 pm_runtime_forbid(th
->dev
);
738 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
741 ida_simple_remove(&intel_th_ida
, th
->id
);
745 EXPORT_SYMBOL_GPL(intel_th_free
);
748 * intel_th_trace_enable() - enable tracing for an output device
749 * @thdev: output device that requests tracing be enabled
751 int intel_th_trace_enable(struct intel_th_device
*thdev
)
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
);
756 if (WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
))
759 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
762 pm_runtime_get_sync(&thdev
->dev
);
763 hubdrv
->enable(hub
, &thdev
->output
);
767 EXPORT_SYMBOL_GPL(intel_th_trace_enable
);
770 * intel_th_trace_disable() - disable tracing for an output device
771 * @thdev: output device that requests tracing be disabled
773 int intel_th_trace_disable(struct intel_th_device
*thdev
)
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
);
778 WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
);
779 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
782 hubdrv
->disable(hub
, &thdev
->output
);
783 pm_runtime_put(&thdev
->dev
);
787 EXPORT_SYMBOL_GPL(intel_th_trace_disable
);
789 int intel_th_set_output(struct intel_th_device
*thdev
,
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
);
795 if (!hubdrv
->set_output
)
798 return hubdrv
->set_output(hub
, master
);
800 EXPORT_SYMBOL_GPL(intel_th_set_output
);
802 static int __init
intel_th_init(void)
804 intel_th_debug_init();
806 return bus_register(&intel_th_bus
);
808 subsys_initcall(intel_th_init
);
810 static void __exit
intel_th_exit(void)
812 intel_th_debug_done();
814 bus_unregister(&intel_th_bus
);
816 module_exit(intel_th_exit
);
818 MODULE_LICENSE("GPL v2");
819 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
820 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");