diff options
author | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2017-08-10 11:28:38 -0400 |
---|---|---|
committer | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2017-08-25 11:47:55 -0400 |
commit | a753bfcfdb1f31d74b5ec87faa19f15e8c7b44a2 (patch) | |
tree | 583341f644da61bb07bc8b6f200c693cfe83cd0d /drivers/hwtracing | |
parent | 8edc514b01e9cfbc037c708e5260f248cbb4d867 (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>
Diffstat (limited to 'drivers/hwtracing')
-rw-r--r-- | drivers/hwtracing/intel_th/core.c | 288 | ||||
-rw-r--r-- | drivers/hwtracing/intel_th/gth.c | 17 | ||||
-rw-r--r-- | drivers/hwtracing/intel_th/intel_th.h | 13 |
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 | ||
104 | static void intel_th_device_remove(struct intel_th_device *thdev); | ||
105 | |||
104 | static int intel_th_remove(struct device *dev) | 106 | static 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 | ||
514 | static int intel_th_populate(struct intel_th *th, struct resource *devres, | 550 | static struct intel_th_device * |
515 | unsigned int ndevres, int irq) | 551 | intel_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; | 625 | fail_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) { | 628 | fail_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 | */ | ||
643 | int 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 | |||
683 | found: | ||
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 | } | ||
692 | EXPORT_SYMBOL_GPL(intel_th_output_enable); | ||
600 | 693 | ||
601 | kill_subdevs: | 694 | static 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 | ||
608 | static int match_devt(struct device *dev, void *data) | 727 | static 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 | ||
694 | err_chrdev: | ||
695 | pm_runtime_forbid(dev); | ||
696 | |||
697 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, | ||
698 | "intel_th/output"); | ||
699 | |||
700 | err_ida: | 820 | err_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) | |||
639 | static int intel_th_gth_probe(struct intel_th_device *thdev) | 639 | static 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(>h->gth_lock); | 662 | spin_lock_init(>h->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 | ||
701 | done: | ||
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); | |||
216 | int intel_th_trace_disable(struct intel_th_device *thdev); | 216 | int intel_th_trace_disable(struct intel_th_device *thdev); |
217 | int intel_th_set_output(struct intel_th_device *thdev, | 217 | int intel_th_set_output(struct intel_th_device *thdev, |
218 | unsigned int master); | 218 | unsigned int master); |
219 | int intel_th_output_enable(struct intel_th *th, unsigned int otype); | ||
219 | 220 | ||
220 | enum { | 221 | enum { |
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 |