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
);
226 module_put(thdrv
->driver
.owner
);
232 static void intel_th_output_deactivate(struct intel_th_device
*thdev
)
234 struct intel_th_driver
*thdrv
=
235 to_intel_th_driver_or_null(thdev
->dev
.driver
);
240 if (thdrv
->deactivate
)
241 thdrv
->deactivate(thdev
);
243 intel_th_trace_disable(thdev
);
245 pm_runtime_put(&thdev
->dev
);
246 module_put(thdrv
->driver
.owner
);
249 static ssize_t
active_show(struct device
*dev
, struct device_attribute
*attr
,
252 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
254 return scnprintf(buf
, PAGE_SIZE
, "%d\n", thdev
->output
.active
);
257 static ssize_t
active_store(struct device
*dev
, struct device_attribute
*attr
,
258 const char *buf
, size_t size
)
260 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
264 ret
= kstrtoul(buf
, 10, &val
);
268 if (!!val
!= thdev
->output
.active
) {
270 ret
= intel_th_output_activate(thdev
);
272 intel_th_output_deactivate(thdev
);
275 return ret
? ret
: size
;
278 static DEVICE_ATTR_RW(active
);
280 static struct attribute
*intel_th_output_attrs
[] = {
282 &dev_attr_active
.attr
,
286 ATTRIBUTE_GROUPS(intel_th_output
);
288 static struct device_type intel_th_output_device_type
= {
289 .name
= "intel_th_output_device",
290 .groups
= intel_th_output_groups
,
291 .release
= intel_th_device_release
,
292 .devnode
= intel_th_output_devnode
,
295 static struct device_type intel_th_switch_device_type
= {
296 .name
= "intel_th_switch_device",
297 .release
= intel_th_device_release
,
300 static struct device_type
*intel_th_device_type
[] = {
301 [INTEL_TH_SOURCE
] = &intel_th_source_device_type
,
302 [INTEL_TH_OUTPUT
] = &intel_th_output_device_type
,
303 [INTEL_TH_SWITCH
] = &intel_th_switch_device_type
,
306 int intel_th_driver_register(struct intel_th_driver
*thdrv
)
308 if (!thdrv
->probe
|| !thdrv
->remove
)
311 thdrv
->driver
.bus
= &intel_th_bus
;
313 return driver_register(&thdrv
->driver
);
315 EXPORT_SYMBOL_GPL(intel_th_driver_register
);
317 void intel_th_driver_unregister(struct intel_th_driver
*thdrv
)
319 driver_unregister(&thdrv
->driver
);
321 EXPORT_SYMBOL_GPL(intel_th_driver_unregister
);
323 static struct intel_th_device
*
324 intel_th_device_alloc(struct intel_th
*th
, unsigned int type
, const char *name
,
327 struct device
*parent
;
328 struct intel_th_device
*thdev
;
330 if (type
== INTEL_TH_SWITCH
)
333 parent
= &th
->hub
->dev
;
335 thdev
= kzalloc(sizeof(*thdev
) + strlen(name
) + 1, GFP_KERNEL
);
342 strcpy(thdev
->name
, name
);
343 device_initialize(&thdev
->dev
);
344 thdev
->dev
.bus
= &intel_th_bus
;
345 thdev
->dev
.type
= intel_th_device_type
[type
];
346 thdev
->dev
.parent
= parent
;
347 thdev
->dev
.dma_mask
= parent
->dma_mask
;
348 thdev
->dev
.dma_parms
= parent
->dma_parms
;
349 dma_set_coherent_mask(&thdev
->dev
, parent
->coherent_dma_mask
);
351 dev_set_name(&thdev
->dev
, "%d-%s%d", th
->id
, name
, id
);
353 dev_set_name(&thdev
->dev
, "%d-%s", th
->id
, name
);
358 static int intel_th_device_add_resources(struct intel_th_device
*thdev
,
359 struct resource
*res
, int nres
)
363 r
= kmemdup(res
, sizeof(*res
) * nres
, GFP_KERNEL
);
368 thdev
->num_resources
= nres
;
373 static void intel_th_device_remove(struct intel_th_device
*thdev
)
375 device_del(&thdev
->dev
);
376 put_device(&thdev
->dev
);
379 static void intel_th_device_free(struct intel_th_device
*thdev
)
381 kfree(thdev
->resource
);
386 * Intel(R) Trace Hub subdevices
388 static const struct intel_th_subdevice
{
390 struct resource res
[3];
396 } intel_th_subdevices
[TH_SUBDEVICE_MAX
] = {
401 .start
= REG_GTH_OFFSET
,
402 .end
= REG_GTH_OFFSET
+ REG_GTH_LENGTH
- 1,
403 .flags
= IORESOURCE_MEM
,
407 .type
= INTEL_TH_SWITCH
,
414 .start
= REG_MSU_OFFSET
,
415 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
416 .flags
= IORESOURCE_MEM
,
419 .start
= BUF_MSU_OFFSET
,
420 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
421 .flags
= IORESOURCE_MEM
,
426 .type
= INTEL_TH_OUTPUT
,
428 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC0_IS_ENABLED
,
434 .start
= REG_MSU_OFFSET
,
435 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
436 .flags
= IORESOURCE_MEM
,
439 .start
= BUF_MSU_OFFSET
,
440 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
441 .flags
= IORESOURCE_MEM
,
446 .type
= INTEL_TH_OUTPUT
,
448 .scrpd
= SCRPD_MEM_IS_PRIM_DEST
| SCRPD_MSC1_IS_ENABLED
,
454 .start
= REG_STH_OFFSET
,
455 .end
= REG_STH_OFFSET
+ REG_STH_LENGTH
- 1,
456 .flags
= IORESOURCE_MEM
,
461 .flags
= IORESOURCE_MEM
,
466 .type
= INTEL_TH_SOURCE
,
472 .start
= REG_PTI_OFFSET
,
473 .end
= REG_PTI_OFFSET
+ REG_PTI_LENGTH
- 1,
474 .flags
= IORESOURCE_MEM
,
479 .type
= INTEL_TH_OUTPUT
,
481 .scrpd
= SCRPD_PTI_IS_PRIM_DEST
,
487 .start
= REG_DCIH_OFFSET
,
488 .end
= REG_DCIH_OFFSET
+ REG_DCIH_LENGTH
- 1,
489 .flags
= IORESOURCE_MEM
,
494 .type
= INTEL_TH_OUTPUT
,
498 #ifdef CONFIG_MODULES
499 static void __intel_th_request_hub_module(struct work_struct
*work
)
501 struct intel_th
*th
= container_of(work
, struct intel_th
,
502 request_module_work
);
504 request_module("intel_th_%s", th
->hub
->name
);
507 static int intel_th_request_hub_module(struct intel_th
*th
)
509 INIT_WORK(&th
->request_module_work
, __intel_th_request_hub_module
);
510 schedule_work(&th
->request_module_work
);
515 static void intel_th_request_hub_module_flush(struct intel_th
*th
)
517 flush_work(&th
->request_module_work
);
520 static inline int intel_th_request_hub_module(struct intel_th
*th
)
525 static inline void intel_th_request_hub_module_flush(struct intel_th
*th
)
528 #endif /* CONFIG_MODULES */
530 static int intel_th_populate(struct intel_th
*th
, struct resource
*devres
,
531 unsigned int ndevres
, int irq
)
533 struct resource res
[3];
534 unsigned int req
= 0;
537 /* create devices for each intel_th_subdevice */
538 for (src
= 0, dst
= 0; src
< ARRAY_SIZE(intel_th_subdevices
); src
++) {
539 const struct intel_th_subdevice
*subdev
=
540 &intel_th_subdevices
[src
];
541 struct intel_th_device
*thdev
;
544 /* only allow SOURCE and SWITCH devices in host mode */
545 if (host_mode
&& subdev
->type
== INTEL_TH_OUTPUT
)
548 thdev
= intel_th_device_alloc(th
, subdev
->type
, subdev
->name
,
555 memcpy(res
, subdev
->res
,
556 sizeof(struct resource
) * subdev
->nres
);
558 for (r
= 0; r
< subdev
->nres
; r
++) {
559 int bar
= TH_MMIO_CONFIG
;
562 * Take .end == 0 to mean 'take the whole bar',
563 * .start then tells us which bar it is. Default to
566 if (!res
[r
].end
&& res
[r
].flags
== IORESOURCE_MEM
) {
569 res
[r
].end
= resource_size(&devres
[bar
]) - 1;
572 if (res
[r
].flags
& IORESOURCE_MEM
) {
573 res
[r
].start
+= devres
[bar
].start
;
574 res
[r
].end
+= devres
[bar
].start
;
576 dev_dbg(th
->dev
, "%s:%d @ %pR\n",
577 subdev
->name
, r
, &res
[r
]);
578 } else if (res
[r
].flags
& IORESOURCE_IRQ
) {
583 err
= intel_th_device_add_resources(thdev
, res
, subdev
->nres
);
585 put_device(&thdev
->dev
);
589 if (subdev
->type
== INTEL_TH_OUTPUT
) {
590 thdev
->dev
.devt
= MKDEV(th
->major
, dst
);
591 thdev
->output
.type
= subdev
->otype
;
592 thdev
->output
.port
= -1;
593 thdev
->output
.scratchpad
= subdev
->scrpd
;
594 } else if (subdev
->type
== INTEL_TH_SWITCH
) {
595 thdev
->host_mode
= host_mode
;
598 err
= device_add(&thdev
->dev
);
600 put_device(&thdev
->dev
);
604 /* need switch driver to be loaded to enumerate the rest */
605 if (subdev
->type
== INTEL_TH_SWITCH
&& !req
) {
607 err
= intel_th_request_hub_module(th
);
612 th
->thdev
[dst
++] = thdev
;
618 for (; dst
>= 0; dst
--)
619 intel_th_device_remove(th
->thdev
[dst
]);
624 static int match_devt(struct device
*dev
, void *data
)
626 dev_t devt
= (dev_t
)(unsigned long)data
;
628 return dev
->devt
== devt
;
631 static int intel_th_output_open(struct inode
*inode
, struct file
*file
)
633 const struct file_operations
*fops
;
634 struct intel_th_driver
*thdrv
;
638 dev
= bus_find_device(&intel_th_bus
, NULL
,
639 (void *)(unsigned long)inode
->i_rdev
,
641 if (!dev
|| !dev
->driver
)
644 thdrv
= to_intel_th_driver(dev
->driver
);
645 fops
= fops_get(thdrv
->fops
);
649 replace_fops(file
, fops
);
651 file
->private_data
= to_intel_th_device(dev
);
653 if (file
->f_op
->open
) {
654 err
= file
->f_op
->open(inode
, file
);
661 static const struct file_operations intel_th_output_fops
= {
662 .open
= intel_th_output_open
,
663 .llseek
= noop_llseek
,
667 * intel_th_alloc() - allocate a new Intel TH device and its subdevices
668 * @dev: parent device
669 * @devres: parent's resources
670 * @ndevres: number of resources
674 intel_th_alloc(struct device
*dev
, struct resource
*devres
,
675 unsigned int ndevres
, int irq
)
680 th
= kzalloc(sizeof(*th
), GFP_KERNEL
);
682 return ERR_PTR(-ENOMEM
);
684 th
->id
= ida_simple_get(&intel_th_ida
, 0, 0, GFP_KERNEL
);
690 th
->major
= __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS
,
691 "intel_th/output", &intel_th_output_fops
);
698 dev_set_drvdata(dev
, th
);
700 pm_runtime_no_callbacks(dev
);
702 pm_runtime_allow(dev
);
704 err
= intel_th_populate(th
, devres
, ndevres
, irq
);
711 pm_runtime_forbid(dev
);
713 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
717 ida_simple_remove(&intel_th_ida
, th
->id
);
724 EXPORT_SYMBOL_GPL(intel_th_alloc
);
726 void intel_th_free(struct intel_th
*th
)
730 intel_th_request_hub_module_flush(th
);
731 for (i
= 0; i
< TH_SUBDEVICE_MAX
; i
++)
732 if (th
->thdev
[i
] && th
->thdev
[i
] != th
->hub
)
733 intel_th_device_remove(th
->thdev
[i
]);
735 intel_th_device_remove(th
->hub
);
737 pm_runtime_get_sync(th
->dev
);
738 pm_runtime_forbid(th
->dev
);
740 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
743 ida_simple_remove(&intel_th_ida
, th
->id
);
747 EXPORT_SYMBOL_GPL(intel_th_free
);
750 * intel_th_trace_enable() - enable tracing for an output device
751 * @thdev: output device that requests tracing be enabled
753 int intel_th_trace_enable(struct intel_th_device
*thdev
)
755 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
756 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
758 if (WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
))
761 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
764 pm_runtime_get_sync(&thdev
->dev
);
765 hubdrv
->enable(hub
, &thdev
->output
);
769 EXPORT_SYMBOL_GPL(intel_th_trace_enable
);
772 * intel_th_trace_disable() - disable tracing for an output device
773 * @thdev: output device that requests tracing be disabled
775 int intel_th_trace_disable(struct intel_th_device
*thdev
)
777 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
778 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
780 WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
);
781 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
784 hubdrv
->disable(hub
, &thdev
->output
);
785 pm_runtime_put(&thdev
->dev
);
789 EXPORT_SYMBOL_GPL(intel_th_trace_disable
);
791 int intel_th_set_output(struct intel_th_device
*thdev
,
794 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
795 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
797 if (!hubdrv
->set_output
)
800 return hubdrv
->set_output(hub
, master
);
802 EXPORT_SYMBOL_GPL(intel_th_set_output
);
804 static int __init
intel_th_init(void)
806 intel_th_debug_init();
808 return bus_register(&intel_th_bus
);
810 subsys_initcall(intel_th_init
);
812 static void __exit
intel_th_exit(void)
814 intel_th_debug_done();
816 bus_unregister(&intel_th_bus
);
818 module_exit(intel_th_exit
);
820 MODULE_LICENSE("GPL v2");
821 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
822 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");