diff options
| -rw-r--r-- | drivers/hwtracing/coresight/coresight-etm4x.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index ebaefb45130f..4db8d6a4d0cb 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c | |||
| @@ -335,12 +335,25 @@ static void etm4_disable_hw(void *info) | |||
| 335 | static int etm4_disable_perf(struct coresight_device *csdev, | 335 | static int etm4_disable_perf(struct coresight_device *csdev, |
| 336 | struct perf_event *event) | 336 | struct perf_event *event) |
| 337 | { | 337 | { |
| 338 | u32 control; | ||
| 339 | struct etm_filters *filters = event->hw.addr_filters; | ||
| 338 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 340 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 339 | 341 | ||
| 340 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) | 342 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) |
| 341 | return -EINVAL; | 343 | return -EINVAL; |
| 342 | 344 | ||
| 343 | etm4_disable_hw(drvdata); | 345 | etm4_disable_hw(drvdata); |
| 346 | |||
| 347 | /* | ||
| 348 | * Check if the start/stop logic was active when the unit was stopped. | ||
| 349 | * That way we can re-enable the start/stop logic when the process is | ||
| 350 | * scheduled again. Configuration of the start/stop logic happens in | ||
| 351 | * function etm4_set_event_filters(). | ||
| 352 | */ | ||
| 353 | control = readl_relaxed(drvdata->base + TRCVICTLR); | ||
| 354 | /* TRCVICTLR::SSSTATUS, bit[9] */ | ||
| 355 | filters->ssstatus = (control & BIT(9)); | ||
| 356 | |||
| 344 | return 0; | 357 | return 0; |
| 345 | } | 358 | } |
| 346 | 359 | ||
| @@ -657,6 +670,27 @@ static void etm4_set_comparator_filter(struct etmv4_config *config, | |||
| 657 | config->viiectlr |= BIT(comparator / 2); | 670 | config->viiectlr |= BIT(comparator / 2); |
| 658 | } | 671 | } |
| 659 | 672 | ||
| 673 | static void etm4_set_start_stop_filter(struct etmv4_config *config, | ||
| 674 | u64 address, int comparator, | ||
| 675 | enum etm_addr_type type) | ||
| 676 | { | ||
| 677 | int shift; | ||
| 678 | u64 access_type = etm4_get_access_type(config); | ||
| 679 | |||
| 680 | /* Configure the comparator */ | ||
| 681 | config->addr_val[comparator] = address; | ||
| 682 | config->addr_acc[comparator] = access_type; | ||
| 683 | config->addr_type[comparator] = type; | ||
| 684 | |||
| 685 | /* | ||
| 686 | * Configure ViewInst Start-Stop control register. | ||
| 687 | * Addresses configured to start tracing go from bit 0 to n-1, | ||
| 688 | * while those configured to stop tracing from 16 to 16 + n-1. | ||
| 689 | */ | ||
| 690 | shift = (type == ETM_ADDR_TYPE_START ? 0 : 16); | ||
| 691 | config->vissctlr |= BIT(shift + comparator); | ||
| 692 | } | ||
| 693 | |||
| 660 | static void etm4_set_default_filter(struct etmv4_config *config) | 694 | static void etm4_set_default_filter(struct etmv4_config *config) |
| 661 | { | 695 | { |
| 662 | u64 start, stop; | 696 | u64 start, stop; |
| @@ -721,6 +755,14 @@ static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type) | |||
| 721 | /* Address range comparators go in pairs */ | 755 | /* Address range comparators go in pairs */ |
| 722 | index += 2; | 756 | index += 2; |
| 723 | break; | 757 | break; |
| 758 | case ETM_ADDR_TYPE_START: | ||
| 759 | case ETM_ADDR_TYPE_STOP: | ||
| 760 | if (config->addr_type[index] == ETM_ADDR_TYPE_NONE) | ||
| 761 | return index; | ||
| 762 | |||
| 763 | /* Start/stop address can have odd indexes */ | ||
| 764 | index += 1; | ||
| 765 | break; | ||
| 724 | default: | 766 | default: |
| 725 | return -EINVAL; | 767 | return -EINVAL; |
| 726 | } | 768 | } |
| @@ -734,6 +776,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | |||
| 734 | struct perf_event *event) | 776 | struct perf_event *event) |
| 735 | { | 777 | { |
| 736 | int i, comparator, ret = 0; | 778 | int i, comparator, ret = 0; |
| 779 | u64 address; | ||
| 737 | struct etmv4_config *config = &drvdata->config; | 780 | struct etmv4_config *config = &drvdata->config; |
| 738 | struct etm_filters *filters = event->hw.addr_filters; | 781 | struct etm_filters *filters = event->hw.addr_filters; |
| 739 | 782 | ||
| @@ -776,6 +819,34 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | |||
| 776 | /* No start-stop filtering for ViewInst */ | 819 | /* No start-stop filtering for ViewInst */ |
| 777 | config->vissctlr = 0x0; | 820 | config->vissctlr = 0x0; |
| 778 | break; | 821 | break; |
| 822 | case ETM_ADDR_TYPE_START: | ||
| 823 | case ETM_ADDR_TYPE_STOP: | ||
| 824 | /* Get the right start or stop address */ | ||
| 825 | address = (type == ETM_ADDR_TYPE_START ? | ||
| 826 | filter->start_addr : | ||
| 827 | filter->stop_addr); | ||
| 828 | |||
| 829 | /* Configure comparator */ | ||
| 830 | etm4_set_start_stop_filter(config, address, | ||
| 831 | comparator, type); | ||
| 832 | |||
| 833 | /* | ||
| 834 | * If filters::ssstatus == 1, trace acquisition was | ||
| 835 | * started but the process was yanked away before the | ||
| 836 | * the stop address was hit. As such the start/stop | ||
| 837 | * logic needs to be re-started so that tracing can | ||
| 838 | * resume where it left. | ||
| 839 | * | ||
| 840 | * The start/stop logic status when a process is | ||
| 841 | * scheduled out is checked in function | ||
| 842 | * etm4_disable_perf(). | ||
| 843 | */ | ||
| 844 | if (filters->ssstatus) | ||
| 845 | config->vinst_ctrl |= BIT(9); | ||
| 846 | |||
| 847 | /* No include/exclude filtering for ViewInst */ | ||
| 848 | config->viiectlr = 0x0; | ||
| 849 | break; | ||
| 779 | default: | 850 | default: |
| 780 | ret = -EINVAL; | 851 | ret = -EINVAL; |
| 781 | goto out; | 852 | goto out; |
