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