Commit b03d541aa45b52e1b723890121a9fe3920eb438b

Authored by Jan Glauber
Committed by Martin Schwidefsky
1 parent 61d84979ab

[S390] oprofile: Allow multiple users of the measurement alert interrupt

Prepare the measurement facility which is currently only used by oprofile
for multiple users.  To achieve that the measurement alert interrupt control
bit needs to be protected.  The measurement alert definitions are moved
to a header file and an interrupt mask is added so that users can discard
interrupts if they are for a different measurement subsystem.

Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

Showing 4 changed files with 59 additions and 30 deletions Side-by-side Diff

arch/s390/include/asm/cpu_mf.h
  1 +#ifndef _ASM_S390_CPU_MF_H
  2 +#define _ASM_S390_CPU_MF_H
  3 +
  4 +#define CPU_MF_INT_SF_MASK 0xffc00000
  5 +
  6 +#define CPU_MF_INT_SF_IAE (1 << 31) /* invalid entry address */
  7 +#define CPU_MF_INT_SF_ISE (1 << 30) /* incorrect SDBT entry */
  8 +#define CPU_MF_INT_SF_PRA (1 << 29) /* program request alert */
  9 +#define CPU_MF_INT_SF_SACA (1 << 23) /* sampler auth. change alert */
  10 +#define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */
  11 +
  12 +#endif
arch/s390/include/asm/irq.h
... ... @@ -45,6 +45,8 @@
45 45 int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
46 46 void service_subclass_irq_register(void);
47 47 void service_subclass_irq_unregister(void);
  48 +void measurement_alert_subclass_register(void);
  49 +void measurement_alert_subclass_unregister(void);
48 50  
49 51 #endif /* _ASM_IRQ_H */
arch/s390/kernel/irq.c
... ... @@ -255,4 +255,27 @@
255 255 spin_unlock(&sc_irq_lock);
256 256 }
257 257 EXPORT_SYMBOL(service_subclass_irq_unregister);
  258 +
  259 +static DEFINE_SPINLOCK(ma_subclass_lock);
  260 +static int ma_subclass_refcount;
  261 +
  262 +void measurement_alert_subclass_register(void)
  263 +{
  264 + spin_lock(&ma_subclass_lock);
  265 + if (!ma_subclass_refcount)
  266 + ctl_set_bit(0, 5);
  267 + ma_subclass_refcount++;
  268 + spin_unlock(&ma_subclass_lock);
  269 +}
  270 +EXPORT_SYMBOL(measurement_alert_subclass_register);
  271 +
  272 +void measurement_alert_subclass_unregister(void)
  273 +{
  274 + spin_lock(&ma_subclass_lock);
  275 + ma_subclass_refcount--;
  276 + if (!ma_subclass_refcount)
  277 + ctl_clear_bit(0, 5);
  278 + spin_unlock(&ma_subclass_lock);
  279 +}
  280 +EXPORT_SYMBOL(measurement_alert_subclass_unregister);
arch/s390/oprofile/hwsampler.c
... ... @@ -17,8 +17,7 @@
17 17 #include <linux/semaphore.h>
18 18 #include <linux/oom.h>
19 19 #include <linux/oprofile.h>
20   -
21   -#include <asm/lowcore.h>
  20 +#include <asm/cpu_mf.h>
22 21 #include <asm/irq.h>
23 22  
24 23 #include "hwsampler.h"
... ... @@ -30,12 +29,6 @@
30 29 #define ALERT_REQ_MASK 0x4000000000000000ul
31 30 #define BUFFER_FULL_MASK 0x8000000000000000ul
32 31  
33   -#define EI_IEA (1 << 31) /* invalid entry address */
34   -#define EI_ISE (1 << 30) /* incorrect SDBT entry */
35   -#define EI_PRA (1 << 29) /* program request alert */
36   -#define EI_SACA (1 << 23) /* sampler authorization change alert */
37   -#define EI_LSDA (1 << 22) /* loss of sample data alert */
38   -
39 32 DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
40 33  
41 34 struct hws_execute_parms {
42 35  
43 36  
... ... @@ -232,10 +225,21 @@
232 225 return (unsigned long *) ret;
233 226 }
234 227  
235   -/* prototypes for external interrupt handler and worker */
236 228 static void hws_ext_handler(struct ext_code ext_code,
237   - unsigned int param32, unsigned long param64);
  229 + unsigned int param32, unsigned long param64)
  230 +{
  231 + struct hws_cpu_buffer *cb = &__get_cpu_var(sampler_cpu_buffer);
238 232  
  233 + if (!(param32 & CPU_MF_INT_SF_MASK))
  234 + return;
  235 +
  236 + kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
  237 + atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
  238 +
  239 + if (hws_wq)
  240 + queue_work(hws_wq, &cb->worker);
  241 +}
  242 +
239 243 static void worker(struct work_struct *work);
240 244  
241 245 static void add_samples_to_oprofile(unsigned cpu, unsigned long *,
... ... @@ -673,18 +677,6 @@
673 677 return rc;
674 678 }
675 679  
676   -static void hws_ext_handler(struct ext_code ext_code,
677   - unsigned int param32, unsigned long param64)
678   -{
679   - struct hws_cpu_buffer *cb;
680   -
681   - kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
682   - cb = &__get_cpu_var(sampler_cpu_buffer);
683   - atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
684   - if (hws_wq)
685   - queue_work(hws_wq, &cb->worker);
686   -}
687   -
688 680 static int check_qsi_on_setup(void)
689 681 {
690 682 int rc;
691 683  
692 684  
693 685  
694 686  
... ... @@ -760,23 +752,23 @@
760 752 if (!sdbt || !*sdbt)
761 753 return -EINVAL;
762 754  
763   - if (ext_params & EI_PRA)
  755 + if (ext_params & CPU_MF_INT_SF_PRA)
764 756 cb->req_alert++;
765 757  
766   - if (ext_params & EI_LSDA)
  758 + if (ext_params & CPU_MF_INT_SF_LSDA)
767 759 cb->loss_of_sample_data++;
768 760  
769   - if (ext_params & EI_IEA) {
  761 + if (ext_params & CPU_MF_INT_SF_IAE) {
770 762 cb->invalid_entry_address++;
771 763 rc = -EINVAL;
772 764 }
773 765  
774   - if (ext_params & EI_ISE) {
  766 + if (ext_params & CPU_MF_INT_SF_ISE) {
775 767 cb->incorrect_sdbt_entry++;
776 768 rc = -EINVAL;
777 769 }
778 770  
779   - if (ext_params & EI_SACA) {
  771 + if (ext_params & CPU_MF_INT_SF_SACA) {
780 772 cb->sample_auth_change_alert++;
781 773 rc = -EINVAL;
782 774 }
... ... @@ -1009,7 +1001,7 @@
1009 1001 if (hws_state != HWS_STOPPED)
1010 1002 goto deallocate_exit;
1011 1003  
1012   - ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
  1004 + measurement_alert_subclass_unregister();
1013 1005 deallocate_sdbt();
1014 1006  
1015 1007 hws_state = HWS_DEALLOCATED;
... ... @@ -1123,7 +1115,7 @@
1123 1115 mutex_lock(&hws_sem);
1124 1116  
1125 1117 if (hws_state == HWS_STOPPED) {
1126   - ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
  1118 + measurement_alert_subclass_unregister();
1127 1119 deallocate_sdbt();
1128 1120 }
1129 1121 if (hws_wq) {
... ... @@ -1198,7 +1190,7 @@
1198 1190 hws_oom = 1;
1199 1191 hws_flush_all = 0;
1200 1192 /* now let them in, 1407 CPUMF external interrupts */
1201   - ctl_set_bit(0, 5); /* set CR0 bit 58 */
  1193 + measurement_alert_subclass_register();
1202 1194  
1203 1195 return 0;
1204 1196 }