]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/kernel/git/benh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Apr 2014 20:47:29 +0000 (13:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Apr 2014 20:47:29 +0000 (13:47 -0700)
Pull powerpc non-virtualized cpuidle from Ben Herrenschmidt:
 "This is the branch I mentioned in my other pull request which contains
  our improved cpuidle support for the "powernv" platform
  (non-virtualized).

  It adds support for the "fast sleep" feature of the processor which
  provides higher power savings than our usual "nap" mode but at the
  cost of losing the timers while asleep, and thus exploits the new
  timer broadcast framework to work around that limitation.

  It's based on a tip timer tree that you seem to have already merged"

* 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  cpuidle/powernv: Parse device tree to setup idle states
  cpuidle/powernv: Add "Fast-Sleep" CPU idle state
  powerpc/powernv: Add OPAL call to resync timebase on wakeup
  powerpc/powernv: Add context management for Fast Sleep
  powerpc: Split timer_interrupt() into timer handling and interrupt handling routines
  powerpc: Implement tick broadcast IPI as a fixed IPI message
  powerpc: Free up the slot of PPC_MSG_CALL_FUNC_SINGLE IPI message

1  2 
arch/powerpc/Kconfig
arch/powerpc/include/asm/opal.h
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/platforms/powernv/opal-wrappers.S
drivers/cpuidle/cpuidle-powernv.c

diff --combined arch/powerpc/Kconfig
index 05e532984c13212b47a87e04412a722e9e6d889a,b84142000a4d2c0dff5a76a42f38c3aa6b77e663..f3d7846bc9b284b6893546f8cca2edd5c72d6809
@@@ -130,6 -130,8 +130,8 @@@ config PP
        select GENERIC_CMOS_UPDATE
        select GENERIC_TIME_VSYSCALL_OLD
        select GENERIC_CLOCKEVENTS
+       select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HAVE_MOD_ARCH_SPECIFIC
@@@ -618,15 -620,6 +620,15 @@@ config CMDLIN
          some command-line options at build time by entering them here.  In
          most cases you will need to specify the root device here.
  
 +config CMDLINE_FORCE
 +      bool "Always use the default kernel command string"
 +      depends on CMDLINE_BOOL
 +      help
 +        Always use the default kernel command string, even if the boot
 +        loader passes other arguments to the kernel.
 +        This is useful if you cannot or don't want to change the
 +        command-line options your boot loader passes to the kernel.
 +
  config EXTRA_TARGETS
        string "Additional default image types"
        help
@@@ -745,6 -738,10 +747,6 @@@ config FSL_LB
          controller.  Also contains some common code used by
          drivers for specific local bus peripherals.
  
 -config FSL_IFC
 -      bool
 -        depends on FSL_SOC
 -
  config FSL_GTM
        bool
        depends on PPC_83xx || QUICC_ENGINE || CPM2
index ffafab037ba860b5eaada654528a8bb9332ee338,c71c72e47d475875ccef284f31a388eb42f41240..fe2aa0b48d2b00e43e47212ddb55ce6c5142537f
@@@ -83,8 -83,6 +83,8 @@@ extern int opal_enter_rtas(struct rtas_
  #define OPAL_INTERNAL_ERROR   -11
  #define OPAL_BUSY_EVENT               -12
  #define OPAL_HARDWARE_FROZEN  -13
 +#define OPAL_WRONG_STATE      -14
 +#define OPAL_ASYNC_COMPLETION -15
  
  /* API Tokens (in r0) */
  #define OPAL_CONSOLE_WRITE                    1
  #define OPAL_LPC_READ                         67
  #define OPAL_LPC_WRITE                                68
  #define OPAL_RETURN_CPU                               69
 +#define OPAL_ELOG_READ                                71
 +#define OPAL_ELOG_WRITE                               72
 +#define OPAL_ELOG_ACK                         73
 +#define OPAL_ELOG_RESEND                      74
 +#define OPAL_ELOG_SIZE                                75
  #define OPAL_FLASH_VALIDATE                   76
  #define OPAL_FLASH_MANAGE                     77
  #define OPAL_FLASH_UPDATE                     78
+ #define OPAL_RESYNC_TIMEBASE                  79
 +#define OPAL_DUMP_INIT                                81
 +#define OPAL_DUMP_INFO                                82
 +#define OPAL_DUMP_READ                                83
 +#define OPAL_DUMP_ACK                         84
  #define OPAL_GET_MSG                          85
  #define OPAL_CHECK_ASYNC_COMPLETION           86
  #define OPAL_SYNC_HOST_REBOOT                 87
 +#define OPAL_SENSOR_READ                      88
 +#define OPAL_GET_PARAM                                89
 +#define OPAL_SET_PARAM                                90
 +#define OPAL_DUMP_RESEND                      91
 +#define OPAL_DUMP_INFO2                               94
  
  #ifndef __ASSEMBLY__
  
@@@ -253,14 -238,11 +254,14 @@@ enum OpalPendingState 
        OPAL_EVENT_EPOW                 = 0x80,
        OPAL_EVENT_LED_STATUS           = 0x100,
        OPAL_EVENT_PCI_ERROR            = 0x200,
 +      OPAL_EVENT_DUMP_AVAIL           = 0x400,
        OPAL_EVENT_MSG_PENDING          = 0x800,
  };
  
  enum OpalMessageType {
 -      OPAL_MSG_ASYNC_COMP             = 0,
 +      OPAL_MSG_ASYNC_COMP = 0,        /* params[0] = token, params[1] = rc,
 +                                       * additional params function-specific
 +                                       */
        OPAL_MSG_MEM_ERR,
        OPAL_MSG_EPOW,
        OPAL_MSG_SHUTDOWN,
@@@ -413,13 -395,6 +414,13 @@@ enum OpalLPCAddressType 
        OPAL_LPC_FW     = 2,
  };
  
 +/* System parameter permission */
 +enum OpalSysparamPerm {
 +      OPAL_SYSPARAM_READ      = 0x1,
 +      OPAL_SYSPARAM_WRITE     = 0x2,
 +      OPAL_SYSPARAM_RW        = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
 +};
 +
  struct opal_msg {
        uint32_t msg_type;
        uint32_t reserved;
@@@ -842,44 -817,23 +843,44 @@@ int64_t opal_pci_next_error(uint64_t ph
  int64_t opal_pci_poll(uint64_t phb_id);
  int64_t opal_return_cpu(void);
  
 -int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val);
 -int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val);
 +int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
 +int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
  
  int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
                       uint32_t addr, uint32_t data, uint32_t sz);
  int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
                      uint32_t addr, __be32 *data, uint32_t sz);
 +
 +int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
 +int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
 +int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
 +int64_t opal_send_ack_elog(uint64_t log_id);
 +void opal_resend_pending_logs(void);
 +
  int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
  int64_t opal_manage_flash(uint8_t op);
  int64_t opal_update_flash(uint64_t blk_list);
 +int64_t opal_dump_init(uint8_t dump_type);
 +int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
 +int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
 +int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
 +int64_t opal_dump_ack(uint32_t dump_id);
 +int64_t opal_dump_resend_notification(void);
  
  int64_t opal_get_msg(uint64_t buffer, size_t size);
  int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
  int64_t opal_sync_host_reboot(void);
 +int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
 +              size_t length);
 +int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
 +              size_t length);
 +int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
 +              uint32_t *sensor_data);
  
  /* Internal functions */
  extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
 +extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
 +                               const char *uname, int depth, void *data);
  
  extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
  extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
@@@ -900,13 -854,6 +901,13 @@@ extern void opal_notifier_update_evt(ui
  extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
  extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
  
 +extern int __opal_async_get_token(void);
 +extern int opal_async_get_token_interruptible(void);
 +extern int __opal_async_release_token(int token);
 +extern int opal_async_release_token(int token);
 +extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
 +extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
 +
  extern void hvc_opal_init_early(void);
  
  struct rtc_time;
@@@ -915,14 -862,11 +916,15 @@@ extern void opal_get_rtc_time(struct rt
  extern unsigned long opal_get_boot_time(void);
  extern void opal_nvram_init(void);
  extern void opal_flash_init(void);
 +extern int opal_elog_init(void);
 +extern void opal_platform_dump_init(void);
 +extern void opal_sys_param_init(void);
  
  extern int opal_machine_check(struct pt_regs *regs);
 +extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
  
  extern void opal_shutdown(void);
+ extern int opal_resync_timebase(void);
  
  extern void opal_lpc_init(void);
  
index 4c34c3c827ad5be65a4f59381c9f485086662fe9,9533d7a9223c3fe2945e8d52783534fd28e7b7bb..d9c650ec7dac2ee047e5c9ab32d4dda61d31d808
@@@ -121,9 -121,10 +121,10 @@@ BEGIN_FTR_SECTIO
        cmpwi   cr1,r13,2
        /* Total loss of HV state is fatal, we could try to use the
         * PIR to locate a PACA, then use an emergency stack etc...
-        * but for now, let's just stay stuck here
+        * OPAL v3 based powernv platforms have new idle states
+        * which fall in this catagory.
         */
-       bgt     cr1,.
+       bgt     cr1,8f
        GET_PACA(r13)
  
  #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        beq     cr1,2f
        b       .power7_wakeup_noloss
  2:    b       .power7_wakeup_loss
+       /* Fast Sleep wakeup on PowerNV */
+ 8:    GET_PACA(r13)
+       b       .power7_wakeup_tb_loss
  9:
  END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
  #endif /* CONFIG_PPC_P7_NAP */
@@@ -164,18 -170,13 +170,18 @@@ BEGIN_FTR_SECTIO
         */
        mfspr   r13,SPRN_SRR1
        rlwinm. r13,r13,47-31,30,31
 +      OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
        beq     9f
  
 +      mfspr   r13,SPRN_SRR1
 +      rlwinm. r13,r13,47-31,30,31
        /* waking up from powersave (nap) state */
        cmpwi   cr1,r13,2
        /* Total loss of HV state is fatal. let's just stay stuck here */
 +      OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
        bgt     cr1,.
  9:
 +      OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
  END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
  #endif /* CONFIG_PPC_P7_NAP */
        EXCEPTION_PROLOG_0(PACA_EXMC)
index 75c89df8d71e95b130dc827e036f25330cc1d6ad,aab54b60334fc1cfb29216a2f06bf8ef78f5aee6..bb90f9a4e0270be18a63a4126841fe81ff84cb12
@@@ -123,23 -123,10 +123,24 @@@ OPAL_CALL(opal_xscom_write,                     OPAL_XSCO
  OPAL_CALL(opal_lpc_read,                      OPAL_LPC_READ);
  OPAL_CALL(opal_lpc_write,                     OPAL_LPC_WRITE);
  OPAL_CALL(opal_return_cpu,                    OPAL_RETURN_CPU);
 +OPAL_CALL(opal_read_elog,                     OPAL_ELOG_READ);
 +OPAL_CALL(opal_send_ack_elog,                 OPAL_ELOG_ACK);
 +OPAL_CALL(opal_get_elog_size,                 OPAL_ELOG_SIZE);
 +OPAL_CALL(opal_resend_pending_logs,           OPAL_ELOG_RESEND);
 +OPAL_CALL(opal_write_elog,                    OPAL_ELOG_WRITE);
  OPAL_CALL(opal_validate_flash,                        OPAL_FLASH_VALIDATE);
  OPAL_CALL(opal_manage_flash,                  OPAL_FLASH_MANAGE);
  OPAL_CALL(opal_update_flash,                  OPAL_FLASH_UPDATE);
+ OPAL_CALL(opal_resync_timebase,                       OPAL_RESYNC_TIMEBASE);
 +OPAL_CALL(opal_dump_init,                     OPAL_DUMP_INIT);
 +OPAL_CALL(opal_dump_info,                     OPAL_DUMP_INFO);
 +OPAL_CALL(opal_dump_info2,                    OPAL_DUMP_INFO2);
 +OPAL_CALL(opal_dump_read,                     OPAL_DUMP_READ);
 +OPAL_CALL(opal_dump_ack,                      OPAL_DUMP_ACK);
  OPAL_CALL(opal_get_msg,                               OPAL_GET_MSG);
  OPAL_CALL(opal_check_completion,              OPAL_CHECK_ASYNC_COMPLETION);
 +OPAL_CALL(opal_dump_resend_notification,      OPAL_DUMP_RESEND);
  OPAL_CALL(opal_sync_host_reboot,              OPAL_SYNC_HOST_REBOOT);
 +OPAL_CALL(opal_sensor_read,                   OPAL_SENSOR_READ);
 +OPAL_CALL(opal_get_param,                     OPAL_GET_PARAM);
 +OPAL_CALL(opal_set_param,                     OPAL_SET_PARAM);
index f48607cd254024f07501bd802112e90991d697b1,fdae1c476e2755e4fd76cb102bdbab83c77fb2ff..719f6fb5b1c35d00108c47a61918741200eae75d
  #include <linux/cpuidle.h>
  #include <linux/cpu.h>
  #include <linux/notifier.h>
+ #include <linux/clockchips.h>
+ #include <linux/of.h>
  
  #include <asm/machdep.h>
  #include <asm/firmware.h>
 +#include <asm/runlatch.h>
  
+ /* Flags and constants used in PowerNV platform */
+ #define MAX_POWERNV_IDLE_STATES       8
+ #define IDLE_USE_INST_NAP     0x00010000 /* Use nap instruction */
+ #define IDLE_USE_INST_SLEEP   0x00020000 /* Use sleep instruction */
  struct cpuidle_driver powernv_idle_driver = {
        .name             = "powernv_idle",
        .owner            = THIS_MODULE,
@@@ -31,14 -38,12 +39,14 @@@ static int snooze_loop(struct cpuidle_d
        local_irq_enable();
        set_thread_flag(TIF_POLLING_NRFLAG);
  
 +      ppc64_runlatch_off();
        while (!need_resched()) {
                HMT_low();
                HMT_very_low();
        }
  
        HMT_medium();
 +      ppc64_runlatch_on();
        clear_thread_flag(TIF_POLLING_NRFLAG);
        smp_mb();
        return index;
@@@ -48,16 -53,40 +56,42 @@@ static int nap_loop(struct cpuidle_devi
                        struct cpuidle_driver *drv,
                        int index)
  {
 +      ppc64_runlatch_off();
        power7_idle();
 +      ppc64_runlatch_on();
        return index;
  }
  
+ static int fastsleep_loop(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
+                               int index)
+ {
+       unsigned long old_lpcr = mfspr(SPRN_LPCR);
+       unsigned long new_lpcr;
+       if (unlikely(system_state < SYSTEM_RUNNING))
+               return index;
+       new_lpcr = old_lpcr;
+       new_lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
+       /* exit powersave upon external interrupt, but not decrementer
+        * interrupt.
+        */
+       new_lpcr |= LPCR_PECE0;
+       mtspr(SPRN_LPCR, new_lpcr);
+       power7_sleep();
+       mtspr(SPRN_LPCR, old_lpcr);
+       return index;
+ }
  /*
   * States for dedicated partition case.
   */
- static struct cpuidle_state powernv_states[] = {
+ static struct cpuidle_state powernv_states[MAX_POWERNV_IDLE_STATES] = {
        { /* Snooze */
                .name = "snooze",
                .desc = "snooze",
                .exit_latency = 0,
                .target_residency = 0,
                .enter = &snooze_loop },
-       { /* NAP */
-               .name = "NAP",
-               .desc = "NAP",
-               .flags = CPUIDLE_FLAG_TIME_VALID,
-               .exit_latency = 10,
-               .target_residency = 100,
-               .enter = &nap_loop },
  };
  
  static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
@@@ -132,19 -154,74 +159,74 @@@ static int powernv_cpuidle_driver_init(
        return 0;
  }
  
+ static int powernv_add_idle_states(void)
+ {
+       struct device_node *power_mgt;
+       struct property *prop;
+       int nr_idle_states = 1; /* Snooze */
+       int dt_idle_states;
+       u32 *flags;
+       int i;
+       /* Currently we have snooze statically defined */
+       power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+       if (!power_mgt) {
+               pr_warn("opal: PowerMgmt Node not found\n");
+               return nr_idle_states;
+       }
+       prop = of_find_property(power_mgt, "ibm,cpu-idle-state-flags", NULL);
+       if (!prop) {
+               pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
+               return nr_idle_states;
+       }
+       dt_idle_states = prop->length / sizeof(u32);
+       flags = (u32 *) prop->value;
+       for (i = 0; i < dt_idle_states; i++) {
+               if (flags[i] & IDLE_USE_INST_NAP) {
+                       /* Add NAP state */
+                       strcpy(powernv_states[nr_idle_states].name, "Nap");
+                       strcpy(powernv_states[nr_idle_states].desc, "Nap");
+                       powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
+                       powernv_states[nr_idle_states].exit_latency = 10;
+                       powernv_states[nr_idle_states].target_residency = 100;
+                       powernv_states[nr_idle_states].enter = &nap_loop;
+                       nr_idle_states++;
+               }
+               if (flags[i] & IDLE_USE_INST_SLEEP) {
+                       /* Add FASTSLEEP state */
+                       strcpy(powernv_states[nr_idle_states].name, "FastSleep");
+                       strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
+                       powernv_states[nr_idle_states].flags =
+                               CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
+                       powernv_states[nr_idle_states].exit_latency = 300;
+                       powernv_states[nr_idle_states].target_residency = 1000000;
+                       powernv_states[nr_idle_states].enter = &fastsleep_loop;
+                       nr_idle_states++;
+               }
+       }
+       return nr_idle_states;
+ }
  /*
   * powernv_idle_probe()
   * Choose state table for shared versus dedicated partition
   */
  static int powernv_idle_probe(void)
  {
        if (cpuidle_disable != IDLE_NO_OVERRIDE)
                return -ENODEV;
  
        if (firmware_has_feature(FW_FEATURE_OPALv3)) {
                cpuidle_state_table = powernv_states;
-               max_idle_state = ARRAY_SIZE(powernv_states);
+               /* Device tree can indicate more idle states */
+               max_idle_state = powernv_add_idle_states();
        } else
                return -ENODEV;