Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/hv-gpci: Fix the H_GET_PERF_COUNTER_INFO hcall return value checks

Running event hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/
in one of the system throws below error:

---Logs---
# perf list | grep hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles
hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=?/[Kernel PMU event]

# perf stat -v -e hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ sleep 2
Using CPUID 00800200
Control descriptor is not initialized
Warning:
hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ event is not supported by the kernel.
failed to read counter hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/

Performance counter stats for 'system wide':

<not supported> hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/

2.000700771 seconds time elapsed

The above error is because of the hcall failure as required
permission "Enable Performance Information Collection" is not set.
Based on current code, single_gpci_request function did not check the
error type incase hcall fails and by default returns EINVAL. But we can
have other reasons for hcall failures like H_AUTHORITY/H_PARAMETER with
detail_rc as GEN_BUF_TOO_SMALL, for which we need to act accordingly.

Fix this issue by adding new checks in the single_gpci_request and
h_gpci_event_init functions.

Result after fix patch changes:

# perf stat -e hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ sleep 2
Error:
No permission to enable hv_gpci/dispatch_timebase_by_processor_processor_time_in_timebase_cycles,phys_processor_idx=0/ event.

Fixes: 220a0c609ad1 ("powerpc/perf: Add support for the hv gpci (get performance counter info) interface")
Reported-by: Akanksha J N <akanksha@linux.ibm.com>
Signed-off-by: Kajol Jain <kjain@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240229122847.101162-1-kjain@linux.ibm.com

authored by

Kajol Jain and committed by
Michael Ellerman
ad86d7ee 4eb20bf3

+27 -2
+27 -2
arch/powerpc/perf/hv-gpci.c
··· 695 695 696 696 ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, 697 697 virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE); 698 + 699 + /* 700 + * ret value as 'H_PARAMETER' with detail_rc as 'GEN_BUF_TOO_SMALL', 701 + * specifies that the current buffer size cannot accommodate 702 + * all the information and a partial buffer returned. 703 + * Since in this function we are only accessing data for a given starting index, 704 + * we don't need to accommodate whole data and can get required count by 705 + * accessing first entry data. 706 + * Hence hcall fails only incase the ret value is other than H_SUCCESS or 707 + * H_PARAMETER with detail_rc value as GEN_BUF_TOO_SMALL(0x1B). 708 + */ 709 + if (ret == H_PARAMETER && be32_to_cpu(arg->params.detail_rc) == 0x1B) 710 + ret = 0; 711 + 698 712 if (ret) { 699 713 pr_devel("hcall failed: 0x%lx\n", ret); 700 714 goto out; ··· 773 759 { 774 760 u64 count; 775 761 u8 length; 762 + unsigned long ret; 776 763 777 764 /* Not our event */ 778 765 if (event->attr.type != event->pmu->type) ··· 804 789 } 805 790 806 791 /* check if the request works... */ 807 - if (single_gpci_request(event_get_request(event), 792 + ret = single_gpci_request(event_get_request(event), 808 793 event_get_starting_index(event), 809 794 event_get_secondary_index(event), 810 795 event_get_counter_info_version(event), 811 796 event_get_offset(event), 812 797 length, 813 - &count)) { 798 + &count); 799 + 800 + /* 801 + * ret value as H_AUTHORITY implies that partition is not permitted to retrieve 802 + * performance information, and required to set 803 + * "Enable Performance Information Collection" option. 804 + */ 805 + if (ret == H_AUTHORITY) 806 + return -EPERM; 807 + 808 + if (ret) { 814 809 pr_devel("gpci hcall failed\n"); 815 810 return -EINVAL; 816 811 }