.. | .. |
---|
439 | 439 | unsigned nres; |
---|
440 | 440 | unsigned type; |
---|
441 | 441 | unsigned otype; |
---|
| 442 | + bool mknode; |
---|
442 | 443 | unsigned scrpd; |
---|
443 | 444 | int id; |
---|
444 | 445 | } intel_th_subdevices[] = { |
---|
.. | .. |
---|
446 | 447 | .nres = 1, |
---|
447 | 448 | .res = { |
---|
448 | 449 | { |
---|
449 | | - /* Handle TSCU from GTH driver */ |
---|
| 450 | + /* Handle TSCU and CTS from GTH driver */ |
---|
450 | 451 | .start = REG_GTH_OFFSET, |
---|
451 | | - .end = REG_TSCU_OFFSET + REG_TSCU_LENGTH - 1, |
---|
| 452 | + .end = REG_CTS_OFFSET + REG_CTS_LENGTH - 1, |
---|
452 | 453 | .flags = IORESOURCE_MEM, |
---|
453 | 454 | }, |
---|
454 | 455 | }, |
---|
.. | .. |
---|
473 | 474 | .name = "msc", |
---|
474 | 475 | .id = 0, |
---|
475 | 476 | .type = INTEL_TH_OUTPUT, |
---|
| 477 | + .mknode = true, |
---|
476 | 478 | .otype = GTH_MSU, |
---|
477 | 479 | .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED, |
---|
478 | 480 | }, |
---|
.. | .. |
---|
493 | 495 | .name = "msc", |
---|
494 | 496 | .id = 1, |
---|
495 | 497 | .type = INTEL_TH_OUTPUT, |
---|
| 498 | + .mknode = true, |
---|
496 | 499 | .otype = GTH_MSU, |
---|
497 | 500 | .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED, |
---|
498 | 501 | }, |
---|
.. | .. |
---|
505 | 508 | .flags = IORESOURCE_MEM, |
---|
506 | 509 | }, |
---|
507 | 510 | { |
---|
508 | | - .start = 1, /* use resource[1] */ |
---|
| 511 | + .start = TH_MMIO_SW, |
---|
509 | 512 | .end = 0, |
---|
510 | 513 | .flags = IORESOURCE_MEM, |
---|
511 | 514 | }, |
---|
512 | 515 | }, |
---|
513 | 516 | .id = -1, |
---|
514 | 517 | .name = "sth", |
---|
| 518 | + .type = INTEL_TH_SOURCE, |
---|
| 519 | + }, |
---|
| 520 | + { |
---|
| 521 | + .nres = 2, |
---|
| 522 | + .res = { |
---|
| 523 | + { |
---|
| 524 | + .start = REG_STH_OFFSET, |
---|
| 525 | + .end = REG_STH_OFFSET + REG_STH_LENGTH - 1, |
---|
| 526 | + .flags = IORESOURCE_MEM, |
---|
| 527 | + }, |
---|
| 528 | + { |
---|
| 529 | + .start = TH_MMIO_RTIT, |
---|
| 530 | + .end = 0, |
---|
| 531 | + .flags = IORESOURCE_MEM, |
---|
| 532 | + }, |
---|
| 533 | + }, |
---|
| 534 | + .id = -1, |
---|
| 535 | + .name = "rtit", |
---|
515 | 536 | .type = INTEL_TH_SOURCE, |
---|
516 | 537 | }, |
---|
517 | 538 | { |
---|
.. | .. |
---|
598 | 619 | struct intel_th_device *thdev; |
---|
599 | 620 | struct resource res[3]; |
---|
600 | 621 | unsigned int req = 0; |
---|
601 | | - bool is64bit = false; |
---|
602 | 622 | int r, err; |
---|
603 | 623 | |
---|
604 | 624 | thdev = intel_th_device_alloc(th, subdev->type, subdev->name, |
---|
.. | .. |
---|
608 | 628 | |
---|
609 | 629 | thdev->drvdata = th->drvdata; |
---|
610 | 630 | |
---|
611 | | - for (r = 0; r < th->num_resources; r++) |
---|
612 | | - if (th->resource[r].flags & IORESOURCE_MEM_64) { |
---|
613 | | - is64bit = true; |
---|
614 | | - break; |
---|
615 | | - } |
---|
616 | | - |
---|
617 | 631 | memcpy(res, subdev->res, |
---|
618 | 632 | sizeof(struct resource) * subdev->nres); |
---|
619 | 633 | |
---|
620 | 634 | for (r = 0; r < subdev->nres; r++) { |
---|
621 | 635 | struct resource *devres = th->resource; |
---|
622 | | - int bar = 0; /* cut subdevices' MMIO from resource[0] */ |
---|
| 636 | + int bar = TH_MMIO_CONFIG; |
---|
623 | 637 | |
---|
624 | 638 | /* |
---|
625 | 639 | * Take .end == 0 to mean 'take the whole bar', |
---|
.. | .. |
---|
628 | 642 | */ |
---|
629 | 643 | if (!res[r].end && res[r].flags == IORESOURCE_MEM) { |
---|
630 | 644 | bar = res[r].start; |
---|
631 | | - if (is64bit) |
---|
632 | | - bar *= 2; |
---|
| 645 | + err = -ENODEV; |
---|
| 646 | + if (bar >= th->num_resources) |
---|
| 647 | + goto fail_put_device; |
---|
633 | 648 | res[r].start = 0; |
---|
634 | 649 | res[r].end = resource_size(&devres[bar]) - 1; |
---|
635 | 650 | } |
---|
.. | .. |
---|
641 | 656 | dev_dbg(th->dev, "%s:%d @ %pR\n", |
---|
642 | 657 | subdev->name, r, &res[r]); |
---|
643 | 658 | } else if (res[r].flags & IORESOURCE_IRQ) { |
---|
644 | | - res[r].start = th->irq; |
---|
| 659 | + /* |
---|
| 660 | + * Only pass on the IRQ if we have useful interrupts: |
---|
| 661 | + * the ones that can be configured via MINTCTL. |
---|
| 662 | + */ |
---|
| 663 | + if (INTEL_TH_CAP(th, has_mintctl) && th->irq != -1) |
---|
| 664 | + res[r].start = th->irq; |
---|
645 | 665 | } |
---|
646 | 666 | } |
---|
647 | 667 | |
---|
.. | .. |
---|
650 | 670 | goto fail_put_device; |
---|
651 | 671 | |
---|
652 | 672 | if (subdev->type == INTEL_TH_OUTPUT) { |
---|
653 | | - thdev->dev.devt = MKDEV(th->major, th->num_thdevs); |
---|
| 673 | + if (subdev->mknode) |
---|
| 674 | + thdev->dev.devt = MKDEV(th->major, th->num_thdevs); |
---|
654 | 675 | thdev->output.type = subdev->otype; |
---|
655 | 676 | thdev->output.port = -1; |
---|
656 | 677 | thdev->output.scratchpad = subdev->scrpd; |
---|
.. | .. |
---|
767 | 788 | |
---|
768 | 789 | thdev = intel_th_subdevice_alloc(th, subdev); |
---|
769 | 790 | /* note: caller should free subdevices from th::thdev[] */ |
---|
770 | | - if (IS_ERR(thdev)) |
---|
| 791 | + if (IS_ERR(thdev)) { |
---|
| 792 | + /* ENODEV for individual subdevices is allowed */ |
---|
| 793 | + if (PTR_ERR(thdev) == -ENODEV) |
---|
| 794 | + continue; |
---|
| 795 | + |
---|
771 | 796 | return PTR_ERR(thdev); |
---|
| 797 | + } |
---|
772 | 798 | |
---|
773 | 799 | th->thdev[th->num_thdevs++] = thdev; |
---|
774 | 800 | } |
---|
775 | 801 | |
---|
776 | 802 | return 0; |
---|
777 | | -} |
---|
778 | | - |
---|
779 | | -static int match_devt(struct device *dev, void *data) |
---|
780 | | -{ |
---|
781 | | - dev_t devt = (dev_t)(unsigned long)data; |
---|
782 | | - |
---|
783 | | - return dev->devt == devt; |
---|
784 | 803 | } |
---|
785 | 804 | |
---|
786 | 805 | static int intel_th_output_open(struct inode *inode, struct file *file) |
---|
.. | .. |
---|
790 | 809 | struct device *dev; |
---|
791 | 810 | int err; |
---|
792 | 811 | |
---|
793 | | - dev = bus_find_device(&intel_th_bus, NULL, |
---|
794 | | - (void *)(unsigned long)inode->i_rdev, |
---|
795 | | - match_devt); |
---|
| 812 | + dev = bus_find_device_by_devt(&intel_th_bus, inode->i_rdev); |
---|
796 | 813 | if (!dev || !dev->driver) |
---|
797 | 814 | return -ENODEV; |
---|
798 | 815 | |
---|
.. | .. |
---|
818 | 835 | .llseek = noop_llseek, |
---|
819 | 836 | }; |
---|
820 | 837 | |
---|
| 838 | +static irqreturn_t intel_th_irq(int irq, void *data) |
---|
| 839 | +{ |
---|
| 840 | + struct intel_th *th = data; |
---|
| 841 | + irqreturn_t ret = IRQ_NONE; |
---|
| 842 | + struct intel_th_driver *d; |
---|
| 843 | + int i; |
---|
| 844 | + |
---|
| 845 | + for (i = 0; i < th->num_thdevs; i++) { |
---|
| 846 | + if (th->thdev[i]->type != INTEL_TH_OUTPUT) |
---|
| 847 | + continue; |
---|
| 848 | + |
---|
| 849 | + d = to_intel_th_driver(th->thdev[i]->dev.driver); |
---|
| 850 | + if (d && d->irq) |
---|
| 851 | + ret |= d->irq(th->thdev[i]); |
---|
| 852 | + } |
---|
| 853 | + |
---|
| 854 | + return ret; |
---|
| 855 | +} |
---|
| 856 | + |
---|
821 | 857 | /** |
---|
822 | 858 | * intel_th_alloc() - allocate a new Intel TH device and its subdevices |
---|
823 | 859 | * @dev: parent device |
---|
824 | | - * @devres: parent's resources |
---|
825 | | - * @ndevres: number of resources |
---|
| 860 | + * @devres: resources indexed by th_mmio_idx |
---|
826 | 861 | * @irq: irq number |
---|
827 | 862 | */ |
---|
828 | 863 | struct intel_th * |
---|
829 | 864 | intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, |
---|
830 | | - struct resource *devres, unsigned int ndevres, int irq) |
---|
| 865 | + struct resource *devres, unsigned int ndevres) |
---|
831 | 866 | { |
---|
| 867 | + int err, r, nr_mmios = 0; |
---|
832 | 868 | struct intel_th *th; |
---|
833 | | - int err, r; |
---|
834 | | - |
---|
835 | | - if (irq == -1) |
---|
836 | | - for (r = 0; r < ndevres; r++) |
---|
837 | | - if (devres[r].flags & IORESOURCE_IRQ) { |
---|
838 | | - irq = devres[r].start; |
---|
839 | | - break; |
---|
840 | | - } |
---|
841 | 869 | |
---|
842 | 870 | th = kzalloc(sizeof(*th), GFP_KERNEL); |
---|
843 | 871 | if (!th) |
---|
.. | .. |
---|
855 | 883 | err = th->major; |
---|
856 | 884 | goto err_ida; |
---|
857 | 885 | } |
---|
| 886 | + th->irq = -1; |
---|
858 | 887 | th->dev = dev; |
---|
859 | 888 | th->drvdata = drvdata; |
---|
860 | 889 | |
---|
861 | | - th->resource = devres; |
---|
862 | | - th->num_resources = ndevres; |
---|
863 | | - th->irq = irq; |
---|
| 890 | + for (r = 0; r < ndevres; r++) |
---|
| 891 | + switch (devres[r].flags & IORESOURCE_TYPE_BITS) { |
---|
| 892 | + case IORESOURCE_MEM: |
---|
| 893 | + th->resource[nr_mmios++] = devres[r]; |
---|
| 894 | + break; |
---|
| 895 | + case IORESOURCE_IRQ: |
---|
| 896 | + err = devm_request_irq(dev, devres[r].start, |
---|
| 897 | + intel_th_irq, IRQF_SHARED, |
---|
| 898 | + dev_name(dev), th); |
---|
| 899 | + if (err) |
---|
| 900 | + goto err_chrdev; |
---|
| 901 | + |
---|
| 902 | + if (th->irq == -1) |
---|
| 903 | + th->irq = devres[r].start; |
---|
| 904 | + th->num_irqs++; |
---|
| 905 | + break; |
---|
| 906 | + default: |
---|
| 907 | + dev_warn(dev, "Unknown resource type %lx\n", |
---|
| 908 | + devres[r].flags); |
---|
| 909 | + break; |
---|
| 910 | + } |
---|
| 911 | + |
---|
| 912 | + th->num_resources = nr_mmios; |
---|
864 | 913 | |
---|
865 | 914 | dev_set_drvdata(dev, th); |
---|
866 | 915 | |
---|
.. | .. |
---|
876 | 925 | } |
---|
877 | 926 | |
---|
878 | 927 | return th; |
---|
| 928 | + |
---|
| 929 | +err_chrdev: |
---|
| 930 | + __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, |
---|
| 931 | + "intel_th/output"); |
---|
879 | 932 | |
---|
880 | 933 | err_ida: |
---|
881 | 934 | ida_simple_remove(&intel_th_ida, th->id); |
---|
.. | .. |
---|
901 | 954 | } |
---|
902 | 955 | |
---|
903 | 956 | th->num_thdevs = 0; |
---|
| 957 | + |
---|
| 958 | + for (i = 0; i < th->num_irqs; i++) |
---|
| 959 | + devm_free_irq(th->dev, th->irq + i, th); |
---|
904 | 960 | |
---|
905 | 961 | pm_runtime_get_sync(th->dev); |
---|
906 | 962 | pm_runtime_forbid(th->dev); |
---|
.. | .. |
---|
937 | 993 | EXPORT_SYMBOL_GPL(intel_th_trace_enable); |
---|
938 | 994 | |
---|
939 | 995 | /** |
---|
| 996 | + * intel_th_trace_switch() - execute a switch sequence |
---|
| 997 | + * @thdev: output device that requests tracing switch |
---|
| 998 | + */ |
---|
| 999 | +int intel_th_trace_switch(struct intel_th_device *thdev) |
---|
| 1000 | +{ |
---|
| 1001 | + struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent); |
---|
| 1002 | + struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); |
---|
| 1003 | + |
---|
| 1004 | + if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH)) |
---|
| 1005 | + return -EINVAL; |
---|
| 1006 | + |
---|
| 1007 | + if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) |
---|
| 1008 | + return -EINVAL; |
---|
| 1009 | + |
---|
| 1010 | + hubdrv->trig_switch(hub, &thdev->output); |
---|
| 1011 | + |
---|
| 1012 | + return 0; |
---|
| 1013 | +} |
---|
| 1014 | +EXPORT_SYMBOL_GPL(intel_th_trace_switch); |
---|
| 1015 | + |
---|
| 1016 | +/** |
---|
940 | 1017 | * intel_th_trace_disable() - disable tracing for an output device |
---|
941 | 1018 | * @thdev: output device that requests tracing be disabled |
---|
942 | 1019 | */ |
---|