aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2017-08-10 11:28:38 -0400
committerAlexander Shishkin <alexander.shishkin@linux.intel.com>2017-08-25 11:47:55 -0400
commita753bfcfdb1f31d74b5ec87faa19f15e8c7b44a2 (patch)
tree583341f644da61bb07bc8b6f200c693cfe83cd0d
parent8edc514b01e9cfbc037c708e5260f248cbb4d867 (diff)
intel_th: Make the switch allocate its subdevices
Instead of allocating devices for every possible output subdevice, allow the switch to allocate only the ones that it knows about. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
-rw-r--r--drivers/hwtracing/intel_th/core.c288
-rw-r--r--drivers/hwtracing/intel_th/gth.c17
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h13
3 files changed, 230 insertions, 88 deletions
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 323d3ac8d4f7..4f569593db01 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -101,17 +101,53 @@ out_pm:
101 return ret; 101 return ret;
102} 102}
103 103
104static void intel_th_device_remove(struct intel_th_device *thdev);
105
104static int intel_th_remove(struct device *dev) 106static int intel_th_remove(struct device *dev)
105{ 107{
106 struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver); 108 struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
107 struct intel_th_device *thdev = to_intel_th_device(dev); 109 struct intel_th_device *thdev = to_intel_th_device(dev);
108 struct intel_th_device *hub = to_intel_th_device(dev->parent); 110 struct intel_th_device *hub = to_intel_th_hub(thdev);
109 int err; 111 int err;
110 112
111 if (thdev->type == INTEL_TH_SWITCH) { 113 if (thdev->type == INTEL_TH_SWITCH) {
114 struct intel_th *th = to_intel_th(hub);
115 int i, lowest;
116
117 /* disconnect outputs */
112 err = device_for_each_child(dev, thdev, intel_th_child_remove); 118 err = device_for_each_child(dev, thdev, intel_th_child_remove);
113 if (err) 119 if (err)
114 return err; 120 return err;
121
122 /*
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.
126 */
127 for (i = 0, lowest = -1; i < th->num_thdevs; i++) {
128 /*
129 * Move the non-output devices from higher up the
130 * th->thdev[] array to lower positions to maintain
131 * a contiguous array.
132 */
133 if (th->thdev[i]->type != INTEL_TH_OUTPUT) {
134 if (lowest >= 0) {
135 th->thdev[lowest] = th->thdev[i];
136 th->thdev[i] = NULL;
137 ++lowest;
138 }
139
140 continue;
141 }
142
143 if (lowest == -1)
144 lowest = i;
145
146 intel_th_device_remove(th->thdev[i]);
147 th->thdev[i] = NULL;
148 }
149
150 th->num_thdevs = lowest;
115 } 151 }
116 152
117 if (thdrv->attr_group) 153 if (thdrv->attr_group)
@@ -377,7 +413,7 @@ static const struct intel_th_subdevice {
377 unsigned otype; 413 unsigned otype;
378 unsigned scrpd; 414 unsigned scrpd;
379 int id; 415 int id;
380} intel_th_subdevices[TH_SUBDEVICE_MAX] = { 416} intel_th_subdevices[] = {
381 { 417 {
382 .nres = 1, 418 .nres = 1,
383 .res = { 419 .res = {
@@ -511,98 +547,181 @@ static inline void intel_th_request_hub_module_flush(struct intel_th *th)
511} 547}
512#endif /* CONFIG_MODULES */ 548#endif /* CONFIG_MODULES */
513 549
514static int intel_th_populate(struct intel_th *th, struct resource *devres, 550static struct intel_th_device *
515 unsigned int ndevres, int irq) 551intel_th_subdevice_alloc(struct intel_th *th,
552 const struct intel_th_subdevice *subdev)
516{ 553{
554 struct intel_th_device *thdev;
517 struct resource res[3]; 555 struct resource res[3];
518 unsigned int req = 0; 556 unsigned int req = 0;
519 int src, dst, err; 557 int r, err;
520 558
521 /* create devices for each intel_th_subdevice */ 559 thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
522 for (src = 0, dst = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) { 560 subdev->id);
523 const struct intel_th_subdevice *subdev = 561 if (!thdev)
524 &intel_th_subdevices[src]; 562 return ERR_PTR(-ENOMEM);
525 struct intel_th_device *thdev;
526 int r;
527 563
528 /* only allow SOURCE and SWITCH devices in host mode */
529 if (host_mode && subdev->type == INTEL_TH_OUTPUT)
530 continue;
531 564
532 thdev = intel_th_device_alloc(th, subdev->type, subdev->name, 565 memcpy(res, subdev->res,
533 subdev->id); 566 sizeof(struct resource) * subdev->nres);
534 if (!thdev) { 567
535 err = -ENOMEM; 568 for (r = 0; r < subdev->nres; r++) {
536 goto kill_subdevs; 569 struct resource *devres = th->resource;
570 int bar = TH_MMIO_CONFIG;
571
572 /*
573 * Take .end == 0 to mean 'take the whole bar',
574 * .start then tells us which bar it is. Default to
575 * TH_MMIO_CONFIG.
576 */
577 if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
578 bar = res[r].start;
579 res[r].start = 0;
580 res[r].end = resource_size(&devres[bar]) - 1;
537 } 581 }
538 582
539 memcpy(res, subdev->res, 583 if (res[r].flags & IORESOURCE_MEM) {
540 sizeof(struct resource) * subdev->nres); 584 res[r].start += devres[bar].start;
585 res[r].end += devres[bar].start;
541 586
542 for (r = 0; r < subdev->nres; r++) { 587 dev_dbg(th->dev, "%s:%d @ %pR\n",
543 int bar = TH_MMIO_CONFIG; 588 subdev->name, r, &res[r]);
589 } else if (res[r].flags & IORESOURCE_IRQ) {
590 res[r].start = th->irq;
591 }
592 }
544 593
545 /* 594 err = intel_th_device_add_resources(thdev, res, subdev->nres);
546 * Take .end == 0 to mean 'take the whole bar', 595 if (err) {
547 * .start then tells us which bar it is. Default to 596 put_device(&thdev->dev);
548 * TH_MMIO_CONFIG. 597 goto fail_put_device;
549 */ 598 }
550 if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
551 bar = res[r].start;
552 res[r].start = 0;
553 res[r].end = resource_size(&devres[bar]) - 1;
554 }
555 599
556 if (res[r].flags & IORESOURCE_MEM) { 600 if (subdev->type == INTEL_TH_OUTPUT) {
557 res[r].start += devres[bar].start; 601 thdev->dev.devt = MKDEV(th->major, th->num_thdevs);
558 res[r].end += devres[bar].start; 602 thdev->output.type = subdev->otype;
603 thdev->output.port = -1;
604 thdev->output.scratchpad = subdev->scrpd;
605 } else if (subdev->type == INTEL_TH_SWITCH) {
606 thdev->host_mode = host_mode;
607 th->hub = thdev;
608 }
559 609
560 dev_dbg(th->dev, "%s:%d @ %pR\n", 610 err = device_add(&thdev->dev);
561 subdev->name, r, &res[r]); 611 if (err) {
562 } else if (res[r].flags & IORESOURCE_IRQ) { 612 put_device(&thdev->dev);
563 res[r].start = irq; 613 goto fail_free_res;
564 } 614 }
565 }
566 615
567 err = intel_th_device_add_resources(thdev, res, subdev->nres); 616 /* need switch driver to be loaded to enumerate the rest */
568 if (err) { 617 if (subdev->type == INTEL_TH_SWITCH && !req) {
569 put_device(&thdev->dev); 618 err = intel_th_request_hub_module(th);
570 goto kill_subdevs; 619 if (!err)
571 } 620 req++;
621 }
572 622
573 if (subdev->type == INTEL_TH_OUTPUT) { 623 return thdev;
574 thdev->dev.devt = MKDEV(th->major, dst); 624
575 thdev->output.type = subdev->otype; 625fail_free_res:
576 thdev->output.port = -1; 626 kfree(thdev->resource);
577 thdev->output.scratchpad = subdev->scrpd; 627
578 } else if (subdev->type == INTEL_TH_SWITCH) { 628fail_put_device:
579 thdev->host_mode = host_mode; 629 put_device(&thdev->dev);
580 } 630
631 return ERR_PTR(err);
632}
581 633
582 err = device_add(&thdev->dev); 634/**
583 if (err) { 635 * intel_th_output_enable() - find and enable a device for a given output type
584 put_device(&thdev->dev); 636 * @th: Intel TH instance
585 goto kill_subdevs; 637 * @otype: output type
638 *
639 * Go through the unallocated output devices, find the first one whos type
640 * matches @otype and instantiate it. These devices are removed when the hub
641 * device is removed, see intel_th_remove().
642 */
643int intel_th_output_enable(struct intel_th *th, unsigned int otype)
644{
645 struct intel_th_device *thdev;
646 int src = 0, dst = 0;
647
648 for (src = 0, dst = 0; dst <= th->num_thdevs; src++, dst++) {
649 for (; src < ARRAY_SIZE(intel_th_subdevices); src++) {
650 if (intel_th_subdevices[src].type != INTEL_TH_OUTPUT)
651 continue;
652
653 if (intel_th_subdevices[src].otype != otype)
654 continue;
655
656 break;
586 } 657 }
587 658
588 /* need switch driver to be loaded to enumerate the rest */ 659 /* no unallocated matching subdevices */
589 if (subdev->type == INTEL_TH_SWITCH && !req) { 660 if (src == ARRAY_SIZE(intel_th_subdevices))
590 th->hub = thdev; 661 return -ENODEV;
591 err = intel_th_request_hub_module(th); 662
592 if (!err) 663 for (; dst < th->num_thdevs; dst++) {
593 req++; 664 if (th->thdev[dst]->type != INTEL_TH_OUTPUT)
665 continue;
666
667 if (th->thdev[dst]->output.type != otype)
668 continue;
669
670 break;
594 } 671 }
595 672
596 th->thdev[dst++] = thdev; 673 /*
674 * intel_th_subdevices[src] matches our requirements and is
675 * not matched in th::thdev[]
676 */
677 if (dst == th->num_thdevs)
678 goto found;
597 } 679 }
598 680
681 return -ENODEV;
682
683found:
684 thdev = intel_th_subdevice_alloc(th, &intel_th_subdevices[src]);
685 if (IS_ERR(thdev))
686 return PTR_ERR(thdev);
687
688 th->thdev[th->num_thdevs++] = thdev;
689
599 return 0; 690 return 0;
691}
692EXPORT_SYMBOL_GPL(intel_th_output_enable);
600 693
601kill_subdevs: 694static int intel_th_populate(struct intel_th *th)
602 for (; dst >= 0; dst--) 695{
603 intel_th_device_remove(th->thdev[dst]); 696 int src;
604 697
605 return err; 698 /* create devices for each intel_th_subdevice */
699 for (src = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) {
700 const struct intel_th_subdevice *subdev =
701 &intel_th_subdevices[src];
702 struct intel_th_device *thdev;
703
704 /* only allow SOURCE and SWITCH devices in host mode */
705 if (host_mode && subdev->type == INTEL_TH_OUTPUT)
706 continue;
707
708 /*
709 * don't enable port OUTPUTs in this path; SWITCH enables them
710 * via intel_th_output_enable()
711 */
712 if (subdev->type == INTEL_TH_OUTPUT &&
713 subdev->otype != GTH_NONE)
714 continue;
715
716 thdev = intel_th_subdevice_alloc(th, subdev);
717 /* note: caller should free subdevices from th::thdev[] */
718 if (IS_ERR(thdev))
719 return PTR_ERR(thdev);
720
721 th->thdev[th->num_thdevs++] = thdev;
722 }
723
724 return 0;
606} 725}
607 726
608static int match_devt(struct device *dev, void *data) 727static int match_devt(struct device *dev, void *data)
@@ -679,24 +798,25 @@ intel_th_alloc(struct device *dev, struct resource *devres,
679 } 798 }
680 th->dev = dev; 799 th->dev = dev;
681 800
801 th->resource = devres;
802 th->num_resources = ndevres;
803 th->irq = irq;
804
682 dev_set_drvdata(dev, th); 805 dev_set_drvdata(dev, th);
683 806
684 pm_runtime_no_callbacks(dev); 807 pm_runtime_no_callbacks(dev);
685 pm_runtime_put(dev); 808 pm_runtime_put(dev);
686 pm_runtime_allow(dev); 809 pm_runtime_allow(dev);
687 810
688 err = intel_th_populate(th, devres, ndevres, irq); 811 err = intel_th_populate(th);
689 if (err) 812 if (err) {
690 goto err_chrdev; 813 /* free the subdevices and undo everything */
814 intel_th_free(th);
815 return ERR_PTR(err);
816 }
691 817
692 return th; 818 return th;
693 819
694err_chrdev:
695 pm_runtime_forbid(dev);
696
697 __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
698 "intel_th/output");
699
700err_ida: 820err_ida:
701 ida_simple_remove(&intel_th_ida, th->id); 821 ida_simple_remove(&intel_th_ida, th->id);
702 822
@@ -712,11 +832,15 @@ void intel_th_free(struct intel_th *th)
712 int i; 832 int i;
713 833
714 intel_th_request_hub_module_flush(th); 834 intel_th_request_hub_module_flush(th);
715 for (i = 0; i < TH_SUBDEVICE_MAX; i++)
716 if (th->thdev[i] && th->thdev[i] != th->hub)
717 intel_th_device_remove(th->thdev[i]);
718 835
719 intel_th_device_remove(th->hub); 836 intel_th_device_remove(th->hub);
837 for (i = 0; i < th->num_thdevs; i++) {
838 if (th->thdev[i] != th->hub)
839 intel_th_device_remove(th->thdev[i]);
840 th->thdev[i] = NULL;
841 }
842
843 th->num_thdevs = 0;
720 844
721 pm_runtime_get_sync(th->dev); 845 pm_runtime_get_sync(th->dev);
722 pm_runtime_forbid(th->dev); 846 pm_runtime_forbid(th->dev);
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index dd32d0bad687..7d9d667fe017 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -639,6 +639,7 @@ intel_th_gth_set_output(struct intel_th_device *thdev, unsigned int master)
639static int intel_th_gth_probe(struct intel_th_device *thdev) 639static int intel_th_gth_probe(struct intel_th_device *thdev)
640{ 640{
641 struct device *dev = &thdev->dev; 641 struct device *dev = &thdev->dev;
642 struct intel_th *th = dev_get_drvdata(dev->parent);
642 struct gth_device *gth; 643 struct gth_device *gth;
643 struct resource *res; 644 struct resource *res;
644 void __iomem *base; 645 void __iomem *base;
@@ -660,6 +661,8 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
660 gth->base = base; 661 gth->base = base;
661 spin_lock_init(&gth->gth_lock); 662 spin_lock_init(&gth->gth_lock);
662 663
664 dev_set_drvdata(dev, gth);
665
663 /* 666 /*
664 * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE 667 * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE
665 * bit. Either way, don't reset HW in this case, and don't export any 668 * bit. Either way, don't reset HW in this case, and don't export any
@@ -667,7 +670,7 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
667 * drivers to ports, see intel_th_gth_assign(). 670 * drivers to ports, see intel_th_gth_assign().
668 */ 671 */
669 if (thdev->host_mode) 672 if (thdev->host_mode)
670 goto done; 673 return 0;
671 674
672 ret = intel_th_gth_reset(gth); 675 ret = intel_th_gth_reset(gth);
673 if (ret) { 676 if (ret) {
@@ -676,7 +679,7 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
676 679
677 thdev->host_mode = true; 680 thdev->host_mode = true;
678 681
679 goto done; 682 return 0;
680 } 683 }
681 684
682 for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) 685 for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++)
@@ -687,6 +690,13 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
687 gth->output[i].index = i; 690 gth->output[i].index = i;
688 gth->output[i].port_type = 691 gth->output[i].port_type =
689 gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port)); 692 gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port));
693 if (gth->output[i].port_type == GTH_NONE)
694 continue;
695
696 ret = intel_th_output_enable(th, gth->output[i].port_type);
697 /* -ENODEV is ok, we just won't have that device enumerated */
698 if (ret && ret != -ENODEV)
699 return ret;
690 } 700 }
691 701
692 if (intel_th_output_attributes(gth) || 702 if (intel_th_output_attributes(gth) ||
@@ -698,9 +708,6 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
698 return -ENOMEM; 708 return -ENOMEM;
699 } 709 }
700 710
701done:
702 dev_set_drvdata(dev, gth);
703
704 return 0; 711 return 0;
705} 712}
706 713
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 6243ac1b8bf1..d44da50be3b0 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -216,6 +216,7 @@ int intel_th_trace_enable(struct intel_th_device *thdev);
216int intel_th_trace_disable(struct intel_th_device *thdev); 216int intel_th_trace_disable(struct intel_th_device *thdev);
217int intel_th_set_output(struct intel_th_device *thdev, 217int intel_th_set_output(struct intel_th_device *thdev,
218 unsigned int master); 218 unsigned int master);
219int intel_th_output_enable(struct intel_th *th, unsigned int otype);
219 220
220enum { 221enum {
221 TH_MMIO_CONFIG = 0, 222 TH_MMIO_CONFIG = 0,
@@ -223,8 +224,9 @@ enum {
223 TH_MMIO_END, 224 TH_MMIO_END,
224}; 225};
225 226
226#define TH_SUBDEVICE_MAX 6
227#define TH_POSSIBLE_OUTPUTS 8 227#define TH_POSSIBLE_OUTPUTS 8
228/* Total number of possible subdevices: outputs + GTH + STH */
229#define TH_SUBDEVICE_MAX (TH_POSSIBLE_OUTPUTS + 2)
228#define TH_CONFIGURABLE_MASTERS 256 230#define TH_CONFIGURABLE_MASTERS 256
229#define TH_MSC_MAX 2 231#define TH_MSC_MAX 2
230 232
@@ -233,6 +235,10 @@ enum {
233 * @dev: driver core's device 235 * @dev: driver core's device
234 * @thdev: subdevices 236 * @thdev: subdevices
235 * @hub: "switch" subdevice (GTH) 237 * @hub: "switch" subdevice (GTH)
238 * @resource: resources of the entire controller
239 * @num_thdevs: number of devices in the @thdev array
240 * @num_resources: number or resources in the @resource array
241 * @irq: irq number
236 * @id: this Intel TH controller's device ID in the system 242 * @id: this Intel TH controller's device ID in the system
237 * @major: device node major for output devices 243 * @major: device node major for output devices
238 */ 244 */
@@ -242,6 +248,11 @@ struct intel_th {
242 struct intel_th_device *thdev[TH_SUBDEVICE_MAX]; 248 struct intel_th_device *thdev[TH_SUBDEVICE_MAX];
243 struct intel_th_device *hub; 249 struct intel_th_device *hub;
244 250
251 struct resource *resource;
252 unsigned int num_thdevs;
253 unsigned int num_resources;
254 int irq;
255
245 int id; 256 int id;
246 int major; 257 int major;
247#ifdef CONFIG_MODULES 258#ifdef CONFIG_MODULES