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/dma-mapping.h>
31 static DEFINE_IDA(intel_th_ida
);
33 static int intel_th_match(struct device
*dev
, struct device_driver
*driver
)
35 struct intel_th_driver
*thdrv
= to_intel_th_driver(driver
);
36 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
38 if (thdev
->type
== INTEL_TH_SWITCH
&&
39 (!thdrv
->enable
|| !thdrv
->disable
))
42 return !strcmp(thdev
->name
, driver
->name
);
45 static int intel_th_child_remove(struct device
*dev
, void *data
)
47 device_release_driver(dev
);
52 static int intel_th_probe(struct device
*dev
)
54 struct intel_th_driver
*thdrv
= to_intel_th_driver(dev
->driver
);
55 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
56 struct intel_th_driver
*hubdrv
;
57 struct intel_th_device
*hub
= NULL
;
60 if (thdev
->type
== INTEL_TH_SWITCH
)
63 hub
= to_intel_th_device(dev
->parent
);
65 if (!hub
|| !hub
->dev
.driver
)
68 hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
70 ret
= thdrv
->probe(to_intel_th_device(dev
));
74 if (thdev
->type
== INTEL_TH_OUTPUT
&&
75 !intel_th_output_assigned(thdev
))
76 ret
= hubdrv
->assign(hub
, thdev
);
81 static int intel_th_remove(struct device
*dev
)
83 struct intel_th_driver
*thdrv
= to_intel_th_driver(dev
->driver
);
84 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
85 struct intel_th_device
*hub
= to_intel_th_device(dev
->parent
);
88 if (thdev
->type
== INTEL_TH_SWITCH
) {
89 err
= device_for_each_child(dev
, thdev
, intel_th_child_remove
);
96 if (intel_th_output_assigned(thdev
)) {
97 struct intel_th_driver
*hubdrv
=
98 to_intel_th_driver(dev
->parent
->driver
);
101 hubdrv
->unassign(hub
, thdev
);
107 static struct bus_type intel_th_bus
= {
110 .match
= intel_th_match
,
111 .probe
= intel_th_probe
,
112 .remove
= intel_th_remove
,
115 static void intel_th_device_free(struct intel_th_device
*thdev
);
117 static void intel_th_device_release(struct device
*dev
)
119 intel_th_device_free(to_intel_th_device(dev
));
122 static struct device_type intel_th_source_device_type
= {
123 .name
= "intel_th_source_device",
124 .release
= intel_th_device_release
,
127 static char *intel_th_output_devnode(struct device
*dev
, umode_t
*mode
,
128 kuid_t
*uid
, kgid_t
*gid
)
130 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
134 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s%d", 0, thdev
->name
,
137 node
= kasprintf(GFP_KERNEL
, "intel_th%d/%s", 0, thdev
->name
);
142 static ssize_t
port_show(struct device
*dev
, struct device_attribute
*attr
,
145 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
147 if (thdev
->output
.port
>= 0)
148 return scnprintf(buf
, PAGE_SIZE
, "%u\n", thdev
->output
.port
);
150 return scnprintf(buf
, PAGE_SIZE
, "unassigned\n");
153 static DEVICE_ATTR_RO(port
);
155 static int intel_th_output_activate(struct intel_th_device
*thdev
)
157 struct intel_th_driver
*thdrv
= to_intel_th_driver(thdev
->dev
.driver
);
160 return thdrv
->activate(thdev
);
162 intel_th_trace_enable(thdev
);
167 static void intel_th_output_deactivate(struct intel_th_device
*thdev
)
169 struct intel_th_driver
*thdrv
= to_intel_th_driver(thdev
->dev
.driver
);
171 if (thdrv
->deactivate
)
172 thdrv
->deactivate(thdev
);
174 intel_th_trace_disable(thdev
);
177 static ssize_t
active_show(struct device
*dev
, struct device_attribute
*attr
,
180 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
182 return scnprintf(buf
, PAGE_SIZE
, "%d\n", thdev
->output
.active
);
185 static ssize_t
active_store(struct device
*dev
, struct device_attribute
*attr
,
186 const char *buf
, size_t size
)
188 struct intel_th_device
*thdev
= to_intel_th_device(dev
);
192 ret
= kstrtoul(buf
, 10, &val
);
196 if (!!val
!= thdev
->output
.active
) {
198 ret
= intel_th_output_activate(thdev
);
200 intel_th_output_deactivate(thdev
);
203 return ret
? ret
: size
;
206 static DEVICE_ATTR_RW(active
);
208 static struct attribute
*intel_th_output_attrs
[] = {
210 &dev_attr_active
.attr
,
214 ATTRIBUTE_GROUPS(intel_th_output
);
216 static struct device_type intel_th_output_device_type
= {
217 .name
= "intel_th_output_device",
218 .groups
= intel_th_output_groups
,
219 .release
= intel_th_device_release
,
220 .devnode
= intel_th_output_devnode
,
223 static struct device_type intel_th_switch_device_type
= {
224 .name
= "intel_th_switch_device",
225 .release
= intel_th_device_release
,
228 static struct device_type
*intel_th_device_type
[] = {
229 [INTEL_TH_SOURCE
] = &intel_th_source_device_type
,
230 [INTEL_TH_OUTPUT
] = &intel_th_output_device_type
,
231 [INTEL_TH_SWITCH
] = &intel_th_switch_device_type
,
234 int intel_th_driver_register(struct intel_th_driver
*thdrv
)
236 if (!thdrv
->probe
|| !thdrv
->remove
)
239 thdrv
->driver
.bus
= &intel_th_bus
;
241 return driver_register(&thdrv
->driver
);
243 EXPORT_SYMBOL_GPL(intel_th_driver_register
);
245 void intel_th_driver_unregister(struct intel_th_driver
*thdrv
)
247 driver_unregister(&thdrv
->driver
);
249 EXPORT_SYMBOL_GPL(intel_th_driver_unregister
);
251 static struct intel_th_device
*
252 intel_th_device_alloc(struct intel_th
*th
, unsigned int type
, const char *name
,
255 struct device
*parent
;
256 struct intel_th_device
*thdev
;
258 if (type
== INTEL_TH_SWITCH
)
261 parent
= &th
->hub
->dev
;
263 thdev
= kzalloc(sizeof(*thdev
) + strlen(name
) + 1, GFP_KERNEL
);
270 strcpy(thdev
->name
, name
);
271 device_initialize(&thdev
->dev
);
272 thdev
->dev
.bus
= &intel_th_bus
;
273 thdev
->dev
.type
= intel_th_device_type
[type
];
274 thdev
->dev
.parent
= parent
;
275 thdev
->dev
.dma_mask
= parent
->dma_mask
;
276 thdev
->dev
.dma_parms
= parent
->dma_parms
;
277 dma_set_coherent_mask(&thdev
->dev
, parent
->coherent_dma_mask
);
279 dev_set_name(&thdev
->dev
, "%d-%s%d", th
->id
, name
, id
);
281 dev_set_name(&thdev
->dev
, "%d-%s", th
->id
, name
);
286 static int intel_th_device_add_resources(struct intel_th_device
*thdev
,
287 struct resource
*res
, int nres
)
291 r
= kmemdup(res
, sizeof(*res
) * nres
, GFP_KERNEL
);
296 thdev
->num_resources
= nres
;
301 static void intel_th_device_remove(struct intel_th_device
*thdev
)
303 device_del(&thdev
->dev
);
304 put_device(&thdev
->dev
);
307 static void intel_th_device_free(struct intel_th_device
*thdev
)
309 kfree(thdev
->resource
);
314 * Intel(R) Trace Hub subdevices
316 static struct intel_th_subdevice
{
318 struct resource res
[3];
323 } intel_th_subdevices
[TH_SUBDEVICE_MAX
] = {
328 .start
= REG_GTH_OFFSET
,
329 .end
= REG_GTH_OFFSET
+ REG_GTH_LENGTH
- 1,
330 .flags
= IORESOURCE_MEM
,
334 .type
= INTEL_TH_SWITCH
,
341 .start
= REG_MSU_OFFSET
,
342 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
343 .flags
= IORESOURCE_MEM
,
346 .start
= BUF_MSU_OFFSET
,
347 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
348 .flags
= IORESOURCE_MEM
,
353 .type
= INTEL_TH_OUTPUT
,
360 .start
= REG_MSU_OFFSET
,
361 .end
= REG_MSU_OFFSET
+ REG_MSU_LENGTH
- 1,
362 .flags
= IORESOURCE_MEM
,
365 .start
= BUF_MSU_OFFSET
,
366 .end
= BUF_MSU_OFFSET
+ BUF_MSU_LENGTH
- 1,
367 .flags
= IORESOURCE_MEM
,
372 .type
= INTEL_TH_OUTPUT
,
379 .start
= REG_STH_OFFSET
,
380 .end
= REG_STH_OFFSET
+ REG_STH_LENGTH
- 1,
381 .flags
= IORESOURCE_MEM
,
386 .flags
= IORESOURCE_MEM
,
391 .type
= INTEL_TH_SOURCE
,
397 .start
= REG_PTI_OFFSET
,
398 .end
= REG_PTI_OFFSET
+ REG_PTI_LENGTH
- 1,
399 .flags
= IORESOURCE_MEM
,
404 .type
= INTEL_TH_OUTPUT
,
411 .start
= REG_DCIH_OFFSET
,
412 .end
= REG_DCIH_OFFSET
+ REG_DCIH_LENGTH
- 1,
413 .flags
= IORESOURCE_MEM
,
418 .type
= INTEL_TH_OUTPUT
,
422 #ifdef CONFIG_MODULES
423 static void __intel_th_request_hub_module(struct work_struct
*work
)
425 struct intel_th
*th
= container_of(work
, struct intel_th
,
426 request_module_work
);
428 request_module("intel_th_%s", th
->hub
->name
);
431 static int intel_th_request_hub_module(struct intel_th
*th
)
433 INIT_WORK(&th
->request_module_work
, __intel_th_request_hub_module
);
434 schedule_work(&th
->request_module_work
);
439 static void intel_th_request_hub_module_flush(struct intel_th
*th
)
441 flush_work(&th
->request_module_work
);
444 static inline int intel_th_request_hub_module(struct intel_th
*th
)
449 static inline void intel_th_request_hub_module_flush(struct intel_th
*th
)
452 #endif /* CONFIG_MODULES */
454 static int intel_th_populate(struct intel_th
*th
, struct resource
*devres
,
455 unsigned int ndevres
, int irq
)
457 struct resource res
[3];
458 unsigned int req
= 0;
461 /* create devices for each intel_th_subdevice */
462 for (i
= 0; i
< ARRAY_SIZE(intel_th_subdevices
); i
++) {
463 struct intel_th_subdevice
*subdev
= &intel_th_subdevices
[i
];
464 struct intel_th_device
*thdev
;
467 thdev
= intel_th_device_alloc(th
, subdev
->type
, subdev
->name
,
474 memcpy(res
, subdev
->res
,
475 sizeof(struct resource
) * subdev
->nres
);
477 for (r
= 0; r
< subdev
->nres
; r
++) {
478 int bar
= TH_MMIO_CONFIG
;
481 * Take .end == 0 to mean 'take the whole bar',
482 * .start then tells us which bar it is. Default to
485 if (!res
[r
].end
&& res
[r
].flags
== IORESOURCE_MEM
) {
488 res
[r
].end
= resource_size(&devres
[bar
]) - 1;
491 if (res
[r
].flags
& IORESOURCE_MEM
) {
492 res
[r
].start
+= devres
[bar
].start
;
493 res
[r
].end
+= devres
[bar
].start
;
495 dev_dbg(th
->dev
, "%s:%d @ %pR\n",
496 subdev
->name
, r
, &res
[r
]);
497 } else if (res
[r
].flags
& IORESOURCE_IRQ
) {
502 err
= intel_th_device_add_resources(thdev
, res
, subdev
->nres
);
504 put_device(&thdev
->dev
);
508 if (subdev
->type
== INTEL_TH_OUTPUT
) {
509 thdev
->dev
.devt
= MKDEV(th
->major
, i
);
510 thdev
->output
.type
= subdev
->otype
;
511 thdev
->output
.port
= -1;
514 err
= device_add(&thdev
->dev
);
516 put_device(&thdev
->dev
);
520 /* need switch driver to be loaded to enumerate the rest */
521 if (subdev
->type
== INTEL_TH_SWITCH
&& !req
) {
523 err
= intel_th_request_hub_module(th
);
528 th
->thdev
[i
] = thdev
;
534 for (i
-- ; i
>= 0; i
--)
535 intel_th_device_remove(th
->thdev
[i
]);
540 static int match_devt(struct device
*dev
, void *data
)
542 dev_t devt
= (dev_t
)(unsigned long)data
;
544 return dev
->devt
== devt
;
547 static int intel_th_output_open(struct inode
*inode
, struct file
*file
)
549 const struct file_operations
*fops
;
550 struct intel_th_driver
*thdrv
;
554 dev
= bus_find_device(&intel_th_bus
, NULL
,
555 (void *)(unsigned long)inode
->i_rdev
,
557 if (!dev
|| !dev
->driver
)
560 thdrv
= to_intel_th_driver(dev
->driver
);
561 fops
= fops_get(thdrv
->fops
);
565 replace_fops(file
, fops
);
567 file
->private_data
= to_intel_th_device(dev
);
569 if (file
->f_op
->open
) {
570 err
= file
->f_op
->open(inode
, file
);
577 static const struct file_operations intel_th_output_fops
= {
578 .open
= intel_th_output_open
,
579 .llseek
= noop_llseek
,
583 * intel_th_alloc() - allocate a new Intel TH device and its subdevices
584 * @dev: parent device
585 * @devres: parent's resources
586 * @ndevres: number of resources
590 intel_th_alloc(struct device
*dev
, struct resource
*devres
,
591 unsigned int ndevres
, int irq
)
596 th
= kzalloc(sizeof(*th
), GFP_KERNEL
);
598 return ERR_PTR(-ENOMEM
);
600 th
->id
= ida_simple_get(&intel_th_ida
, 0, 0, GFP_KERNEL
);
606 th
->major
= __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS
,
607 "intel_th/output", &intel_th_output_fops
);
614 err
= intel_th_populate(th
, devres
, ndevres
, irq
);
621 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
625 ida_simple_remove(&intel_th_ida
, th
->id
);
632 EXPORT_SYMBOL_GPL(intel_th_alloc
);
634 void intel_th_free(struct intel_th
*th
)
638 intel_th_request_hub_module_flush(th
);
639 for (i
= 0; i
< TH_SUBDEVICE_MAX
; i
++)
640 if (th
->thdev
[i
] != th
->hub
)
641 intel_th_device_remove(th
->thdev
[i
]);
643 intel_th_device_remove(th
->hub
);
645 __unregister_chrdev(th
->major
, 0, TH_POSSIBLE_OUTPUTS
,
648 ida_simple_remove(&intel_th_ida
, th
->id
);
652 EXPORT_SYMBOL_GPL(intel_th_free
);
655 * intel_th_trace_enable() - enable tracing for an output device
656 * @thdev: output device that requests tracing be enabled
658 int intel_th_trace_enable(struct intel_th_device
*thdev
)
660 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
661 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
663 if (WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
))
666 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
669 hubdrv
->enable(hub
, &thdev
->output
);
673 EXPORT_SYMBOL_GPL(intel_th_trace_enable
);
676 * intel_th_trace_disable() - disable tracing for an output device
677 * @thdev: output device that requests tracing be disabled
679 int intel_th_trace_disable(struct intel_th_device
*thdev
)
681 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
682 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
684 WARN_ON_ONCE(hub
->type
!= INTEL_TH_SWITCH
);
685 if (WARN_ON_ONCE(thdev
->type
!= INTEL_TH_OUTPUT
))
688 hubdrv
->disable(hub
, &thdev
->output
);
692 EXPORT_SYMBOL_GPL(intel_th_trace_disable
);
694 int intel_th_set_output(struct intel_th_device
*thdev
,
697 struct intel_th_device
*hub
= to_intel_th_device(thdev
->dev
.parent
);
698 struct intel_th_driver
*hubdrv
= to_intel_th_driver(hub
->dev
.driver
);
700 if (!hubdrv
->set_output
)
703 return hubdrv
->set_output(hub
, master
);
705 EXPORT_SYMBOL_GPL(intel_th_set_output
);
707 static int __init
intel_th_init(void)
709 intel_th_debug_init();
711 return bus_register(&intel_th_bus
);
713 subsys_initcall(intel_th_init
);
715 static void __exit
intel_th_exit(void)
717 intel_th_debug_done();
719 bus_unregister(&intel_th_bus
);
721 module_exit(intel_th_exit
);
723 MODULE_LICENSE("GPL v2");
724 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
725 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");