diff options
author | Jacob Pan <jacob.jun.pan@linux.intel.com> | 2016-02-24 16:31:36 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-03-08 18:26:43 -0500 |
commit | f14a1396d8f19b6c53593045eba86d10360a0cee (patch) | |
tree | 6928de190e4775d90666fb001c3243e72e00aff7 | |
parent | 16ccbd87c2e5d95f40f3b7a90f40cc2b34b89a22 (diff) |
powercap/rapl: reduce ipi calls
Reduce remote CPU calls for MSR access by combining read
modify write into one function.
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/powercap/intel_rapl.c | 119 |
1 files changed, 85 insertions, 34 deletions
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 6c592dc71aee..a50e644ae07a 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c | |||
@@ -133,6 +133,12 @@ struct rapl_domain_data { | |||
133 | unsigned long timestamp; | 133 | unsigned long timestamp; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | struct msrl_action { | ||
137 | u32 msr_no; | ||
138 | u64 clear_mask; | ||
139 | u64 set_mask; | ||
140 | int err; | ||
141 | }; | ||
136 | 142 | ||
137 | #define DOMAIN_STATE_INACTIVE BIT(0) | 143 | #define DOMAIN_STATE_INACTIVE BIT(0) |
138 | #define DOMAIN_STATE_POWER_LIMIT_SET BIT(1) | 144 | #define DOMAIN_STATE_POWER_LIMIT_SET BIT(1) |
@@ -800,35 +806,62 @@ static int rapl_read_data_raw(struct rapl_domain *rd, | |||
800 | return 0; | 806 | return 0; |
801 | } | 807 | } |
802 | 808 | ||
809 | |||
810 | static int msrl_update_safe(u32 msr_no, u64 clear_mask, u64 set_mask) | ||
811 | { | ||
812 | int err; | ||
813 | u64 val; | ||
814 | |||
815 | err = rdmsrl_safe(msr_no, &val); | ||
816 | if (err) | ||
817 | goto out; | ||
818 | |||
819 | val &= ~clear_mask; | ||
820 | val |= set_mask; | ||
821 | |||
822 | err = wrmsrl_safe(msr_no, val); | ||
823 | |||
824 | out: | ||
825 | return err; | ||
826 | } | ||
827 | |||
828 | static void msrl_update_func(void *info) | ||
829 | { | ||
830 | struct msrl_action *ma = info; | ||
831 | |||
832 | ma->err = msrl_update_safe(ma->msr_no, ma->clear_mask, ma->set_mask); | ||
833 | } | ||
834 | |||
803 | /* Similar use of primitive info in the read counterpart */ | 835 | /* Similar use of primitive info in the read counterpart */ |
804 | static int rapl_write_data_raw(struct rapl_domain *rd, | 836 | static int rapl_write_data_raw(struct rapl_domain *rd, |
805 | enum rapl_primitives prim, | 837 | enum rapl_primitives prim, |
806 | unsigned long long value) | 838 | unsigned long long value) |
807 | { | 839 | { |
808 | u64 msr_val; | ||
809 | u32 msr; | ||
810 | struct rapl_primitive_info *rp = &rpi[prim]; | 840 | struct rapl_primitive_info *rp = &rpi[prim]; |
811 | int cpu; | 841 | int cpu; |
842 | u64 bits; | ||
843 | struct msrl_action ma; | ||
844 | int ret; | ||
812 | 845 | ||
813 | cpu = find_active_cpu_on_package(rd->package_id); | 846 | cpu = find_active_cpu_on_package(rd->package_id); |
814 | if (cpu < 0) | 847 | if (cpu < 0) |
815 | return cpu; | 848 | return cpu; |
816 | msr = rd->msrs[rp->id]; | ||
817 | if (rdmsrl_safe_on_cpu(cpu, msr, &msr_val)) { | ||
818 | dev_dbg(&rd->power_zone.dev, | ||
819 | "failed to read msr 0x%x on cpu %d\n", msr, cpu); | ||
820 | return -EIO; | ||
821 | } | ||
822 | value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1); | ||
823 | msr_val &= ~rp->mask; | ||
824 | msr_val |= value << rp->shift; | ||
825 | if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) { | ||
826 | dev_dbg(&rd->power_zone.dev, | ||
827 | "failed to write msr 0x%x on cpu %d\n", msr, cpu); | ||
828 | return -EIO; | ||
829 | } | ||
830 | 849 | ||
831 | return 0; | 850 | bits = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1); |
851 | bits |= bits << rp->shift; | ||
852 | memset(&ma, 0, sizeof(ma)); | ||
853 | |||
854 | ma.msr_no = rd->msrs[rp->id]; | ||
855 | ma.clear_mask = rp->mask; | ||
856 | ma.set_mask = bits; | ||
857 | |||
858 | ret = smp_call_function_single(cpu, msrl_update_func, &ma, 1); | ||
859 | if (ret) | ||
860 | WARN_ON_ONCE(ret); | ||
861 | else | ||
862 | ret = ma.err; | ||
863 | |||
864 | return ret; | ||
832 | } | 865 | } |
833 | 866 | ||
834 | /* | 867 | /* |
@@ -893,6 +926,21 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu) | |||
893 | return 0; | 926 | return 0; |
894 | } | 927 | } |
895 | 928 | ||
929 | static void power_limit_irq_save_cpu(void *info) | ||
930 | { | ||
931 | u32 l, h = 0; | ||
932 | struct rapl_package *rp = (struct rapl_package *)info; | ||
933 | |||
934 | /* save the state of PLN irq mask bit before disabling it */ | ||
935 | rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | ||
936 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) { | ||
937 | rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE; | ||
938 | rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED; | ||
939 | } | ||
940 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | ||
941 | wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | ||
942 | } | ||
943 | |||
896 | 944 | ||
897 | /* REVISIT: | 945 | /* REVISIT: |
898 | * When package power limit is set artificially low by RAPL, LVT | 946 | * When package power limit is set artificially low by RAPL, LVT |
@@ -906,7 +954,6 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu) | |||
906 | 954 | ||
907 | static void package_power_limit_irq_save(int package_id) | 955 | static void package_power_limit_irq_save(int package_id) |
908 | { | 956 | { |
909 | u32 l, h = 0; | ||
910 | int cpu; | 957 | int cpu; |
911 | struct rapl_package *rp; | 958 | struct rapl_package *rp; |
912 | 959 | ||
@@ -920,20 +967,30 @@ static void package_power_limit_irq_save(int package_id) | |||
920 | cpu = find_active_cpu_on_package(package_id); | 967 | cpu = find_active_cpu_on_package(package_id); |
921 | if (cpu < 0) | 968 | if (cpu < 0) |
922 | return; | 969 | return; |
923 | /* save the state of PLN irq mask bit before disabling it */ | 970 | if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) |
924 | rdmsr_safe_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | 971 | return; |
925 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) { | 972 | |
926 | rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE; | 973 | smp_call_function_single(cpu, power_limit_irq_save_cpu, rp, 1); |
927 | rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED; | 974 | } |
928 | } | 975 | |
929 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | 976 | static void power_limit_irq_restore_cpu(void *info) |
930 | wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | 977 | { |
978 | u32 l, h = 0; | ||
979 | struct rapl_package *rp = (struct rapl_package *)info; | ||
980 | |||
981 | rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | ||
982 | |||
983 | if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE) | ||
984 | l |= PACKAGE_THERM_INT_PLN_ENABLE; | ||
985 | else | ||
986 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | ||
987 | |||
988 | wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | ||
931 | } | 989 | } |
932 | 990 | ||
933 | /* restore per package power limit interrupt enable state */ | 991 | /* restore per package power limit interrupt enable state */ |
934 | static void package_power_limit_irq_restore(int package_id) | 992 | static void package_power_limit_irq_restore(int package_id) |
935 | { | 993 | { |
936 | u32 l, h; | ||
937 | int cpu; | 994 | int cpu; |
938 | struct rapl_package *rp; | 995 | struct rapl_package *rp; |
939 | 996 | ||
@@ -951,14 +1008,8 @@ static void package_power_limit_irq_restore(int package_id) | |||
951 | /* irq enable state not saved, nothing to restore */ | 1008 | /* irq enable state not saved, nothing to restore */ |
952 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) | 1009 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) |
953 | return; | 1010 | return; |
954 | rdmsr_safe_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | ||
955 | |||
956 | if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE) | ||
957 | l |= PACKAGE_THERM_INT_PLN_ENABLE; | ||
958 | else | ||
959 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | ||
960 | 1011 | ||
961 | wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | 1012 | smp_call_function_single(cpu, power_limit_irq_restore_cpu, rp, 1); |
962 | } | 1013 | } |
963 | 1014 | ||
964 | static void set_floor_freq_default(struct rapl_domain *rd, bool mode) | 1015 | static void set_floor_freq_default(struct rapl_domain *rd, bool mode) |