Merge branches 'acpi-pm' and 'pm-genirq'
[cascardo/linux.git] / arch / s390 / kernel / smp.c
index 243c7e5..6fd9e60 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/debug.h>
 #include <asm/os_info.h>
 #include <asm/sigp.h>
+#include <asm/idle.h>
 #include "entry.h"
 
 enum {
@@ -82,7 +83,8 @@ DEFINE_MUTEX(smp_cpu_state_mutex);
 /*
  * Signal processor helper functions.
  */
-static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
+static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm,
+                                   u32 *status)
 {
        int cc;
 
@@ -178,6 +180,9 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
                        goto out;
        }
 #else
+       if (MACHINE_HAS_VX)
+               lc->vector_save_area_addr =
+                       (unsigned long) &lc->vector_save_area;
        if (vdso_alloc_per_cpu(lc))
                goto out;
 #endif
@@ -333,12 +338,6 @@ int smp_vcpu_scheduled(int cpu)
        return pcpu_running(pcpu_devices + cpu);
 }
 
-void smp_yield(void)
-{
-       if (MACHINE_HAS_DIAG44)
-               asm volatile("diag 0,0,0x44");
-}
-
 void smp_yield_cpu(int cpu)
 {
        if (MACHINE_HAS_DIAG9C)
@@ -517,35 +516,53 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
 static void __init smp_get_save_area(int cpu, u16 address)
 {
        void *lc = pcpu_devices[0].lowcore;
-       struct save_area *save_area;
+       struct save_area_ext *sa_ext;
+       unsigned long vx_sa;
 
        if (is_kdump_kernel())
                return;
        if (!OLDMEM_BASE && (address == boot_cpu_address ||
                             ipl_info.type != IPL_TYPE_FCP_DUMP))
                return;
-       save_area = dump_save_area_create(cpu);
-       if (!save_area)
+       sa_ext = dump_save_area_create(cpu);
+       if (!sa_ext)
                panic("could not allocate memory for save area\n");
        if (address == boot_cpu_address) {
                /* Copy the registers of the boot cpu. */
-               copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
+               copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
                                 SAVE_AREA_BASE - PAGE_SIZE, 0);
+               if (MACHINE_HAS_VX)
+                       save_vx_regs_safe(sa_ext->vx_regs);
                return;
        }
        /* Get the registers of a non-boot cpu. */
        __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
-       memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
+       memcpy_real(&sa_ext->sa, lc + SAVE_AREA_BASE, sizeof(sa_ext->sa));
+       if (!MACHINE_HAS_VX)
+               return;
+       /* Get the VX registers */
+       vx_sa = __get_free_page(GFP_KERNEL);
+       if (!vx_sa)
+               panic("could not allocate memory for VX save area\n");
+       __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL);
+       memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs));
+       free_page(vx_sa);
 }
 
 int smp_store_status(int cpu)
 {
+       unsigned long vx_sa;
        struct pcpu *pcpu;
 
        pcpu = pcpu_devices + cpu;
        if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
                              0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
                return -EIO;
+       if (!MACHINE_HAS_VX)
+               return 0;
+       vx_sa = __pa(pcpu->lowcore->vector_save_area_addr);
+       __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
+                         vx_sa, NULL);
        return 0;
 }
 
@@ -667,7 +684,7 @@ static void smp_start_secondary(void *cpuvoid)
        cpu_init();
        preempt_disable();
        init_cpu_timer();
-       init_cpu_vtimer();
+       vtime_init();
        pfault_init();
        notify_cpu_starting(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
@@ -726,6 +743,7 @@ int __cpu_disable(void)
        cregs[6]  &= ~0xff000000UL;     /* disable all I/O interrupts */
        cregs[14] &= ~0x1f000000UL;     /* disable most machine checks */
        __ctl_load(cregs, 0, 15);
+       clear_cpu_flag(CIF_NOHZ_DELAY);
        return 0;
 }
 
@@ -898,42 +916,6 @@ static struct attribute_group cpu_common_attr_group = {
        .attrs = cpu_common_attrs,
 };
 
-static ssize_t show_idle_count(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-       unsigned long long idle_count;
-       unsigned int sequence;
-
-       do {
-               sequence = ACCESS_ONCE(idle->sequence);
-               idle_count = ACCESS_ONCE(idle->idle_count);
-               if (ACCESS_ONCE(idle->clock_idle_enter))
-                       idle_count++;
-       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
-       return sprintf(buf, "%llu\n", idle_count);
-}
-static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
-
-static ssize_t show_idle_time(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-       unsigned long long now, idle_time, idle_enter, idle_exit;
-       unsigned int sequence;
-
-       do {
-               now = get_tod_clock();
-               sequence = ACCESS_ONCE(idle->sequence);
-               idle_time = ACCESS_ONCE(idle->idle_time);
-               idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
-               idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
-       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
-       idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
-       return sprintf(buf, "%llu\n", idle_time >> 12);
-}
-static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
-
 static struct attribute *cpu_online_attrs[] = {
        &dev_attr_idle_count.attr,
        &dev_attr_idle_time_us.attr,