Merge remote-tracking branch 'scott/next' into next
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sun, 23 Mar 2014 23:26:10 +0000 (10:26 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sun, 23 Mar 2014 23:26:10 +0000 (10:26 +1100)
Freescale updates from Scott. Mostly support for critical
and machine check exceptions on 64-bit BookE, some new
PCI suspend/resume work and misc bits.

42 files changed:
Documentation/ABI/testing/sysfs-bus-event_source-devices-events
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci [new file with mode: 0644]
MAINTAINERS
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/configs/pseries_le_defconfig
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/traps.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/perf/Makefile
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/hv-24x7-catalog.h [new file with mode: 0644]
arch/powerpc/perf/hv-24x7.c [new file with mode: 0644]
arch/powerpc/perf/hv-24x7.h [new file with mode: 0644]
arch/powerpc/perf/hv-common.c [new file with mode: 0644]
arch/powerpc/perf/hv-common.h [new file with mode: 0644]
arch/powerpc/perf/hv-gpci.c [new file with mode: 0644]
arch/powerpc/perf/hv-gpci.h [new file with mode: 0644]
arch/powerpc/perf/power7-events-list.h
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/powernv/Makefile
arch/powerpc/platforms/powernv/opal-async.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-sensor.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-sysparam.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/pseries/Kconfig
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ibmpowernv.c [new file with mode: 0644]
fs/sysfs/group.c

index 3c1cc24361bdf0ce40f13a1260fbdf98c90e7e3b..7b40a3cbc26a8026cd818535d1e27f51261353e2 100644 (file)
@@ -57,6 +57,523 @@ What:               /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
                /sys/devices/cpu/events/PM_LD_REF_L1
                /sys/devices/cpu/events/PM_RUN_CYC
                /sys/devices/cpu/events/PM_RUN_INST_CMPL
+               /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_ALL
+               /sys/devices/cpu/events/PM_GCT_UTIL_7_TO_10_SLOTS
+               /sys/devices/cpu/events/PM_PMC2_SAVED
+               /sys/devices/cpu/events/PM_VSU0_16FLOP
+               /sys/devices/cpu/events/PM_MRK_LSU_DERAT_MISS
+               /sys/devices/cpu/events/PM_MRK_ST_CMPL
+               /sys/devices/cpu/events/PM_NEST_PAIR3_ADD
+               /sys/devices/cpu/events/PM_L2_ST_DISP
+               /sys/devices/cpu/events/PM_L2_CASTOUT_MOD
+               /sys/devices/cpu/events/PM_ISEG
+               /sys/devices/cpu/events/PM_MRK_INST_TIMEO
+               /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_ADDR
+               /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM
+               /sys/devices/cpu/events/PM_IERAT_WR_64K
+               /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16M
+               /sys/devices/cpu/events/PM_IERAT_MISS
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_LMEM
+               /sys/devices/cpu/events/PM_FLOP
+               /sys/devices/cpu/events/PM_THRD_PRIO_4_5_CYC
+               /sys/devices/cpu/events/PM_BR_PRED_TA
+               /sys/devices/cpu/events/PM_EXT_INT
+               /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV
+               /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC
+               /sys/devices/cpu/events/PM_LSU1_LDF
+               /sys/devices/cpu/events/PM_IC_WRITE_ALL
+               /sys/devices/cpu/events/PM_LSU0_SRQ_STFWD
+               /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_DATA_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_VSU1_SCAL_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_VSU0_8FLOP
+               /sys/devices/cpu/events/PM_POWER_EVENT1
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD_BAL
+               /sys/devices/cpu/events/PM_VSU1_2FLOP
+               /sys/devices/cpu/events/PM_LWSYNC_HELD
+               /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_INST_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_IERAT_XLATE_WR_16MPLUS
+               /sys/devices/cpu/events/PM_IC_REQ_ALL
+               /sys/devices/cpu/events/PM_DSLB_MISS
+               /sys/devices/cpu/events/PM_L3_MISS
+               /sys/devices/cpu/events/PM_LSU0_L1_PREF
+               /sys/devices/cpu/events/PM_VSU_SCALAR_SINGLE_ISSUED
+               /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE
+               /sys/devices/cpu/events/PM_L2_INST
+               /sys/devices/cpu/events/PM_VSU0_FRSP
+               /sys/devices/cpu/events/PM_FLUSH_DISP
+               /sys/devices/cpu/events/PM_PTEG_FROM_L2MISS
+               /sys/devices/cpu/events/PM_VSU1_DQ_ISSUED
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM
+               /sys/devices/cpu/events/PM_LSU_FLUSH_ULD
+               /sys/devices/cpu/events/PM_PTEG_FROM_LMEM
+               /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16M
+               /sys/devices/cpu/events/PM_THRD_ALL_RUN_CYC
+               /sys/devices/cpu/events/PM_MEM0_PREFETCH_DISP
+               /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC_COUNT
+               /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_VSU_FRSP
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_PMC1_OVERFLOW
+               /sys/devices/cpu/events/PM_VSU0_SINGLE
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3MISS
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_VSU0_VECTOR_SP_ISSUED
+               /sys/devices/cpu/events/PM_VSU1_FEST
+               /sys/devices/cpu/events/PM_MRK_INST_DISP
+               /sys/devices/cpu/events/PM_VSU0_COMPLEX_ISSUED
+               /sys/devices/cpu/events/PM_LSU1_FLUSH_UST
+               /sys/devices/cpu/events/PM_FXU_IDLE
+               /sys/devices/cpu/events/PM_LSU0_FLUSH_ULD
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC
+               /sys/devices/cpu/events/PM_LSU1_REJECT_LMQ_FULL
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_INST_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_SHL_CREATED
+               /sys/devices/cpu/events/PM_L2_ST_HIT
+               /sys/devices/cpu/events/PM_DATA_FROM_DMEM
+               /sys/devices/cpu/events/PM_L3_LD_MISS
+               /sys/devices/cpu/events/PM_FXU1_BUSY_FXU0_IDLE
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD_RES
+               /sys/devices/cpu/events/PM_L2_SN_SX_I_DONE
+               /sys/devices/cpu/events/PM_STCX_CMPL
+               /sys/devices/cpu/events/PM_VSU0_2FLOP
+               /sys/devices/cpu/events/PM_L3_PREF_MISS
+               /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_CYC
+               /sys/devices/cpu/events/PM_LSU_REJECT_ERAT_MISS
+               /sys/devices/cpu/events/PM_L1_ICACHE_MISS
+               /sys/devices/cpu/events/PM_LSU1_FLUSH_SRQ
+               /sys/devices/cpu/events/PM_LD_REF_L1_LSU0
+               /sys/devices/cpu/events/PM_VSU0_FEST
+               /sys/devices/cpu/events/PM_VSU_VECTOR_SINGLE_ISSUED
+               /sys/devices/cpu/events/PM_FREQ_UP
+               /sys/devices/cpu/events/PM_DATA_FROM_LMEM
+               /sys/devices/cpu/events/PM_LSU1_LDX
+               /sys/devices/cpu/events/PM_PMC3_OVERFLOW
+               /sys/devices/cpu/events/PM_MRK_BR_MPRED
+               /sys/devices/cpu/events/PM_SHL_MATCH
+               /sys/devices/cpu/events/PM_MRK_BR_TAKEN
+               /sys/devices/cpu/events/PM_ISLB_MISS
+               /sys/devices/cpu/events/PM_DISP_HELD_THERMAL
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_LSU1_SRQ_STFWD
+               /sys/devices/cpu/events/PM_PTEG_FROM_DMEM
+               /sys/devices/cpu/events/PM_VSU_2FLOP
+               /sys/devices/cpu/events/PM_GCT_FULL_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3_CYC
+               /sys/devices/cpu/events/PM_LSU_SRQ_S0_ALLOC
+               /sys/devices/cpu/events/PM_MRK_DERAT_MISS_4K
+               /sys/devices/cpu/events/PM_BR_MPRED_TA
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2MISS
+               /sys/devices/cpu/events/PM_DPU_HELD_POWER
+               /sys/devices/cpu/events/PM_MRK_VSU_FIN
+               /sys/devices/cpu/events/PM_LSU_SRQ_S0_VALID
+               /sys/devices/cpu/events/PM_GCT_EMPTY_CYC
+               /sys/devices/cpu/events/PM_IOPS_DISP
+               /sys/devices/cpu/events/PM_RUN_SPURR
+               /sys/devices/cpu/events/PM_PTEG_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_VSU0_1FLOP
+               /sys/devices/cpu/events/PM_SNOOP_TLBIE
+               /sys/devices/cpu/events/PM_DATA_FROM_L3MISS
+               /sys/devices/cpu/events/PM_VSU_SINGLE
+               /sys/devices/cpu/events/PM_DTLB_MISS_16G
+               /sys/devices/cpu/events/PM_FLUSH
+               /sys/devices/cpu/events/PM_L2_LD_HIT
+               /sys/devices/cpu/events/PM_NEST_PAIR2_AND
+               /sys/devices/cpu/events/PM_VSU1_1FLOP
+               /sys/devices/cpu/events/PM_IC_PREF_REQ
+               /sys/devices/cpu/events/PM_L3_LD_HIT
+               /sys/devices/cpu/events/PM_DISP_HELD
+               /sys/devices/cpu/events/PM_L2_LD
+               /sys/devices/cpu/events/PM_LSU_FLUSH_SRQ
+               /sys/devices/cpu/events/PM_BC_PLUS_8_CONV
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD_CYC
+               /sys/devices/cpu/events/PM_L2_RCST_BUSY_RC_FULL
+               /sys/devices/cpu/events/PM_TB_BIT_TRANS
+               /sys/devices/cpu/events/PM_THERMAL_MAX
+               /sys/devices/cpu/events/PM_LSU1_FLUSH_ULD
+               /sys/devices/cpu/events/PM_LSU1_REJECT_LHS
+               /sys/devices/cpu/events/PM_LSU_LRQ_S0_ALLOC
+               /sys/devices/cpu/events/PM_L3_CO_L31
+               /sys/devices/cpu/events/PM_POWER_EVENT4
+               /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_BR_UNCOND
+               /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_ALLOC
+               /sys/devices/cpu/events/PM_PMC4_REWIND
+               /sys/devices/cpu/events/PM_L2_RCLD_DISP
+               /sys/devices/cpu/events/PM_THRD_PRIO_2_3_CYC
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2MISS
+               /sys/devices/cpu/events/PM_IC_DEMAND_L2_BHT_REDIRECT
+               /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_IC_PREF_CANCEL_L2
+               /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC_COUNT
+               /sys/devices/cpu/events/PM_BR_PRED_CCACHE
+               /sys/devices/cpu/events/PM_GCT_UTIL_1_TO_2_SLOTS
+               /sys/devices/cpu/events/PM_MRK_ST_CMPL_INT
+               /sys/devices/cpu/events/PM_LSU_TWO_TABLEWALK_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3MISS
+               /sys/devices/cpu/events/PM_LSU_SET_MPRED
+               /sys/devices/cpu/events/PM_FLUSH_DISP_TLBIE
+               /sys/devices/cpu/events/PM_VSU1_FCONV
+               /sys/devices/cpu/events/PM_DERAT_MISS_16G
+               /sys/devices/cpu/events/PM_INST_FROM_LMEM
+               /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_REDIRECT
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2
+               /sys/devices/cpu/events/PM_PTEG_FROM_L2
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR_CYC
+               /sys/devices/cpu/events/PM_MRK_DTLB_MISS_4K
+               /sys/devices/cpu/events/PM_VSU0_FPSCR
+               /sys/devices/cpu/events/PM_VSU1_VECT_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_MEM0_RQ_DISP
+               /sys/devices/cpu/events/PM_L2_LD_MISS
+               /sys/devices/cpu/events/PM_VMX_RESULT_SAT_1
+               /sys/devices/cpu/events/PM_L1_PREF
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM_CYC
+               /sys/devices/cpu/events/PM_GRP_IC_MISS_NONSPEC
+               /sys/devices/cpu/events/PM_PB_NODE_PUMP
+               /sys/devices/cpu/events/PM_SHL_MERGED
+               /sys/devices/cpu/events/PM_NEST_PAIR1_ADD
+               /sys/devices/cpu/events/PM_DATA_FROM_L3
+               /sys/devices/cpu/events/PM_LSU_FLUSH
+               /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_COUNT
+               /sys/devices/cpu/events/PM_PMC2_OVERFLOW
+               /sys/devices/cpu/events/PM_LSU_LDF
+               /sys/devices/cpu/events/PM_POWER_EVENT3
+               /sys/devices/cpu/events/PM_DISP_WT
+               /sys/devices/cpu/events/PM_IC_BANK_CONFLICT
+               /sys/devices/cpu/events/PM_BR_MPRED_CR_TA
+               /sys/devices/cpu/events/PM_L2_INST_MISS
+               /sys/devices/cpu/events/PM_NEST_PAIR2_ADD
+               /sys/devices/cpu/events/PM_MRK_LSU_FLUSH
+               /sys/devices/cpu/events/PM_L2_LDST
+               /sys/devices/cpu/events/PM_INST_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_VSU0_FIN
+               /sys/devices/cpu/events/PM_VSU1_FCONV
+               /sys/devices/cpu/events/PM_INST_FROM_RMEM
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD_TLBIE
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM_CYC
+               /sys/devices/cpu/events/PM_BR_PRED_CR
+               /sys/devices/cpu/events/PM_LSU_REJECT
+               /sys/devices/cpu/events/PM_GCT_UTIL_3_TO_6_SLOTS
+               /sys/devices/cpu/events/PM_CMPLU_STALL_END_GCT_NOSLOT
+               /sys/devices/cpu/events/PM_LSU0_REJECT_LMQ_FULL
+               /sys/devices/cpu/events/PM_VSU_FEST
+               /sys/devices/cpu/events/PM_NEST_PAIR0_AND
+               /sys/devices/cpu/events/PM_PTEG_FROM_L3
+               /sys/devices/cpu/events/PM_POWER_EVENT2
+               /sys/devices/cpu/events/PM_IC_PREF_CANCEL_PAGE
+               /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV
+               /sys/devices/cpu/events/PM_MRK_GRP_CMPL
+               /sys/devices/cpu/events/PM_VSU0_SCAL_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_GRP_DISP
+               /sys/devices/cpu/events/PM_LSU0_LDX
+               /sys/devices/cpu/events/PM_DATA_FROM_L2
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_VSU0_VECT_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_VSU1_2FLOP_DOUBLE
+               /sys/devices/cpu/events/PM_THRD_PRIO_6_7_CYC
+               /sys/devices/cpu/events/PM_BC_PLUS_8_RSLV_TAKEN
+               /sys/devices/cpu/events/PM_BR_MPRED_CR
+               /sys/devices/cpu/events/PM_L3_CO_MEM
+               /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_LSU_SRQ_FULL_CYC
+               /sys/devices/cpu/events/PM_TABLEWALK_CYC
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RMEM
+               /sys/devices/cpu/events/PM_LSU_SRQ_STFWD
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_RMEM
+               /sys/devices/cpu/events/PM_FXU0_FIN
+               /sys/devices/cpu/events/PM_LSU1_L1_SW_PREF
+               /sys/devices/cpu/events/PM_PTEG_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_PMC5_OVERFLOW
+               /sys/devices/cpu/events/PM_LD_REF_L1_LSU1
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_DATA_FROM_RMEM
+               /sys/devices/cpu/events/PM_VSU0_SCAL_SINGLE_ISSUED
+               /sys/devices/cpu/events/PM_BR_MPRED_LSTACK
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD_CYC
+               /sys/devices/cpu/events/PM_LSU0_FLUSH_UST
+               /sys/devices/cpu/events/PM_LSU_NCST
+               /sys/devices/cpu/events/PM_BR_TAKEN
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_LMEM
+               /sys/devices/cpu/events/PM_DTLB_MISS_4K
+               /sys/devices/cpu/events/PM_PMC4_SAVED
+               /sys/devices/cpu/events/PM_VSU1_PERMUTE_ISSUED
+               /sys/devices/cpu/events/PM_SLB_MISS
+               /sys/devices/cpu/events/PM_LSU1_FLUSH_LRQ
+               /sys/devices/cpu/events/PM_DTLB_MISS
+               /sys/devices/cpu/events/PM_VSU1_FRSP
+               /sys/devices/cpu/events/PM_VSU_VECTOR_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_L2_CASTOUT_SHR
+               /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_VSU1_STF
+               /sys/devices/cpu/events/PM_ST_FIN
+               /sys/devices/cpu/events/PM_PTEG_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_L2_LOC_GUESS_WRONG
+               /sys/devices/cpu/events/PM_MRK_STCX_FAIL
+               /sys/devices/cpu/events/PM_LSU0_REJECT_LHS
+               /sys/devices/cpu/events/PM_IC_PREF_CANCEL_HIT
+               /sys/devices/cpu/events/PM_L3_PREF_BUSY
+               /sys/devices/cpu/events/PM_MRK_BRU_FIN
+               /sys/devices/cpu/events/PM_LSU1_NCLD
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_LSU_NCLD
+               /sys/devices/cpu/events/PM_LSU_LDX
+               /sys/devices/cpu/events/PM_L2_LOC_GUESS_CORRECT
+               /sys/devices/cpu/events/PM_THRESH_TIMEO
+               /sys/devices/cpu/events/PM_L3_PREF_ST
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD_SYNC
+               /sys/devices/cpu/events/PM_VSU_SIMPLE_ISSUED
+               /sys/devices/cpu/events/PM_VSU1_SINGLE
+               /sys/devices/cpu/events/PM_DATA_TABLEWALK_CYC
+               /sys/devices/cpu/events/PM_L2_RC_ST_DONE
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_MOD
+               /sys/devices/cpu/events/PM_LARX_LSU1
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD
+               /sys/devices/cpu/events/PM_DERAT_MISS_4K
+               /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_ADDR
+               /sys/devices/cpu/events/PM_SEG_EXCEPTION
+               /sys/devices/cpu/events/PM_FLUSH_DISP_SB
+               /sys/devices/cpu/events/PM_L2_DC_INV
+               /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_DSEG
+               /sys/devices/cpu/events/PM_BR_PRED_LSTACK
+               /sys/devices/cpu/events/PM_VSU0_STF
+               /sys/devices/cpu/events/PM_LSU_FX_FIN
+               /sys/devices/cpu/events/PM_DERAT_MISS_16M
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_GCT_UTIL_11_PLUS_SLOTS
+               /sys/devices/cpu/events/PM_INST_FROM_L3
+               /sys/devices/cpu/events/PM_MRK_IFU_FIN
+               /sys/devices/cpu/events/PM_ITLB_MISS
+               /sys/devices/cpu/events/PM_VSU_STF
+               /sys/devices/cpu/events/PM_LSU_FLUSH_UST
+               /sys/devices/cpu/events/PM_L2_LDST_MISS
+               /sys/devices/cpu/events/PM_FXU1_FIN
+               /sys/devices/cpu/events/PM_SHL_DEALLOCATED
+               /sys/devices/cpu/events/PM_L2_SN_M_WR_DONE
+               /sys/devices/cpu/events/PM_LSU_REJECT_SET_MPRED
+               /sys/devices/cpu/events/PM_L3_PREF_LD
+               /sys/devices/cpu/events/PM_L2_SN_M_RD_DONE
+               /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16G
+               /sys/devices/cpu/events/PM_VSU_FCONV
+               /sys/devices/cpu/events/PM_ANY_THRD_RUN_CYC
+               /sys/devices/cpu/events/PM_LSU_LMQ_FULL_CYC
+               /sys/devices/cpu/events/PM_MRK_LSU_REJECT_LHS
+               /sys/devices/cpu/events/PM_MRK_LD_MISS_L1_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2_CYC
+               /sys/devices/cpu/events/PM_INST_IMC_MATCH_DISP
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM_CYC
+               /sys/devices/cpu/events/PM_VSU0_SIMPLE_ISSUED
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_VSU_FMA_DOUBLE
+               /sys/devices/cpu/events/PM_VSU_4FLOP
+               /sys/devices/cpu/events/PM_VSU1_FIN
+               /sys/devices/cpu/events/PM_NEST_PAIR1_AND
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_MOD
+               /sys/devices/cpu/events/PM_PTEG_FROM_RMEM
+               /sys/devices/cpu/events/PM_LSU_LRQ_S0_VALID
+               /sys/devices/cpu/events/PM_LSU0_LDF
+               /sys/devices/cpu/events/PM_FLUSH_COMPLETION
+               /sys/devices/cpu/events/PM_ST_MISS_L1
+               /sys/devices/cpu/events/PM_L2_NODE_PUMP
+               /sys/devices/cpu/events/PM_INST_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC
+               /sys/devices/cpu/events/PM_VSU1_DENORM
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR_CYC
+               /sys/devices/cpu/events/PM_NEST_PAIR0_ADD
+               /sys/devices/cpu/events/PM_INST_FROM_L3MISS
+               /sys/devices/cpu/events/PM_EE_OFF_EXT_INT
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_DMEM
+               /sys/devices/cpu/events/PM_INST_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_PMC6_OVERFLOW
+               /sys/devices/cpu/events/PM_VSU_2FLOP_DOUBLE
+               /sys/devices/cpu/events/PM_TLB_MISS
+               /sys/devices/cpu/events/PM_FXU_BUSY
+               /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_OTHER
+               /sys/devices/cpu/events/PM_LSU_REJECT_LMQ_FULL
+               /sys/devices/cpu/events/PM_IC_RELOAD_SHR
+               /sys/devices/cpu/events/PM_GRP_MRK
+               /sys/devices/cpu/events/PM_MRK_ST_NEST
+               /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV
+               /sys/devices/cpu/events/PM_LSU0_FLUSH_LRQ
+               /sys/devices/cpu/events/PM_LARX_LSU0
+               /sys/devices/cpu/events/PM_IBUF_FULL_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR_CYC
+               /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_ALLOC
+               /sys/devices/cpu/events/PM_GRP_MRK_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR_CYC
+               /sys/devices/cpu/events/PM_L2_GLOB_GUESS_CORRECT
+               /sys/devices/cpu/events/PM_LSU_REJECT_LHS
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3
+               /sys/devices/cpu/events/PM_FREQ_DOWN
+               /sys/devices/cpu/events/PM_PB_RETRY_NODE_PUMP
+               /sys/devices/cpu/events/PM_INST_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_MRK_INST_ISSUED
+               /sys/devices/cpu/events/PM_PTEG_FROM_L3MISS
+               /sys/devices/cpu/events/PM_RUN_PURR
+               /sys/devices/cpu/events/PM_MRK_GRP_IC_MISS
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3
+               /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_LSU_FLUSH_LRQ
+               /sys/devices/cpu/events/PM_MRK_DERAT_MISS_64K
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_MOD
+               /sys/devices/cpu/events/PM_L2_ST_MISS
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_LWSYNC
+               /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE
+               /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_LRQ
+               /sys/devices/cpu/events/PM_INST_IMC_MATCH_CMPL
+               /sys/devices/cpu/events/PM_NEST_PAIR3_AND
+               /sys/devices/cpu/events/PM_PB_RETRY_SYS_PUMP
+               /sys/devices/cpu/events/PM_MRK_INST_FIN
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_INST_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_MRK_DTLB_MISS_64K
+               /sys/devices/cpu/events/PM_LSU_FIN
+               /sys/devices/cpu/events/PM_MRK_LSU_REJECT
+               /sys/devices/cpu/events/PM_L2_CO_FAIL_BUSY
+               /sys/devices/cpu/events/PM_MEM0_WQ_DISP
+               /sys/devices/cpu/events/PM_DATA_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_THERMAL_WARN
+               /sys/devices/cpu/events/PM_VSU0_4FLOP
+               /sys/devices/cpu/events/PM_BR_MPRED_CCACHE
+               /sys/devices/cpu/events/PM_L1_DEMAND_WRITE
+               /sys/devices/cpu/events/PM_FLUSH_BR_MPRED
+               /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16G
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DMEM
+               /sys/devices/cpu/events/PM_L2_RCST_DISP
+               /sys/devices/cpu/events/PM_LSU_PARTIAL_CDF
+               /sys/devices/cpu/events/PM_DISP_CLB_HELD_SB
+               /sys/devices/cpu/events/PM_VSU0_FMA_DOUBLE
+               /sys/devices/cpu/events/PM_FXU0_BUSY_FXU1_IDLE
+               /sys/devices/cpu/events/PM_IC_DEMAND_CYC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_UST
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3MISS
+               /sys/devices/cpu/events/PM_VSU_DENORM
+               /sys/devices/cpu/events/PM_MRK_LSU_PARTIAL_CDF
+               /sys/devices/cpu/events/PM_INST_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_IC_PREF_WRITE
+               /sys/devices/cpu/events/PM_BR_PRED
+               /sys/devices/cpu/events/PM_INST_FROM_DMEM
+               /sys/devices/cpu/events/PM_IC_PREF_CANCEL_ALL
+               /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_CONFIRM
+               /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_SRQ
+               /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC
+               /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_OTHER
+               /sys/devices/cpu/events/PM_VSU1_DD_ISSUED
+               /sys/devices/cpu/events/PM_PTEG_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_DATA_FROM_L21_SHR
+               /sys/devices/cpu/events/PM_LSU0_NCLD
+               /sys/devices/cpu/events/PM_VSU1_4FLOP
+               /sys/devices/cpu/events/PM_VSU1_8FLOP
+               /sys/devices/cpu/events/PM_VSU_8FLOP
+               /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_CYC
+               /sys/devices/cpu/events/PM_DTLB_MISS_64K
+               /sys/devices/cpu/events/PM_THRD_CONC_RUN_INST
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2
+               /sys/devices/cpu/events/PM_PB_SYS_PUMP
+               /sys/devices/cpu/events/PM_VSU_FIN
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_THRD_PRIO_0_1_CYC
+               /sys/devices/cpu/events/PM_DERAT_MISS_64K
+               /sys/devices/cpu/events/PM_PMC2_REWIND
+               /sys/devices/cpu/events/PM_INST_FROM_L2
+               /sys/devices/cpu/events/PM_GRP_BR_MPRED_NONSPEC
+               /sys/devices/cpu/events/PM_INST_DISP
+               /sys/devices/cpu/events/PM_MEM0_RD_CANCEL_TOTAL
+               /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM
+               /sys/devices/cpu/events/PM_L1_DCACHE_RELOAD_VALID
+               /sys/devices/cpu/events/PM_VSU_SCALAR_DOUBLE_ISSUED
+               /sys/devices/cpu/events/PM_L3_PREF_HIT
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_MOD
+               /sys/devices/cpu/events/PM_MRK_FXU_FIN
+               /sys/devices/cpu/events/PM_PMC4_OVERFLOW
+               /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3
+               /sys/devices/cpu/events/PM_LSU0_LMQ_LHR_MERGE
+               /sys/devices/cpu/events/PM_BTAC_HIT
+               /sys/devices/cpu/events/PM_L3_RD_BUSY
+               /sys/devices/cpu/events/PM_LSU0_L1_SW_PREF
+               /sys/devices/cpu/events/PM_INST_FROM_L2MISS
+               /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_ALLOC
+               /sys/devices/cpu/events/PM_L2_ST
+               /sys/devices/cpu/events/PM_VSU0_DENORM
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_BR_PRED_CR_TA
+               /sys/devices/cpu/events/PM_VSU0_FCONV
+               /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_ULD
+               /sys/devices/cpu/events/PM_BTAC_MISS
+               /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC_COUNT
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2
+               /sys/devices/cpu/events/PM_LSU_DCACHE_RELOAD_VALID
+               /sys/devices/cpu/events/PM_VSU_FMA
+               /sys/devices/cpu/events/PM_LSU0_FLUSH_SRQ
+               /sys/devices/cpu/events/PM_LSU1_L1_PREF
+               /sys/devices/cpu/events/PM_IOPS_CMPL
+               /sys/devices/cpu/events/PM_L2_SYS_PUMP
+               /sys/devices/cpu/events/PM_L2_RCLD_BUSY_RC_FULL
+               /sys/devices/cpu/events/PM_LSU_LMQ_S0_ALLOC
+               /sys/devices/cpu/events/PM_FLUSH_DISP_SYNC
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD_CYC
+               /sys/devices/cpu/events/PM_L2_IC_INV
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD_CYC
+               /sys/devices/cpu/events/PM_L3_PREF_LDST
+               /sys/devices/cpu/events/PM_LSU_SRQ_EMPTY_CYC
+               /sys/devices/cpu/events/PM_LSU_LMQ_S0_VALID
+               /sys/devices/cpu/events/PM_FLUSH_PARTIAL
+               /sys/devices/cpu/events/PM_VSU1_FMA_DOUBLE
+               /sys/devices/cpu/events/PM_1PLUS_PPC_DISP
+               /sys/devices/cpu/events/PM_DATA_FROM_L2MISS
+               /sys/devices/cpu/events/PM_SUSPENDED
+               /sys/devices/cpu/events/PM_VSU0_FMA
+               /sys/devices/cpu/events/PM_STCX_FAIL
+               /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV_DOUBLE
+               /sys/devices/cpu/events/PM_DC_PREF_DST
+               /sys/devices/cpu/events/PM_VSU1_SCAL_SINGLE_ISSUED
+               /sys/devices/cpu/events/PM_L3_HIT
+               /sys/devices/cpu/events/PM_L2_GLOB_GUESS_WRONG
+               /sys/devices/cpu/events/PM_MRK_DFU_FIN
+               /sys/devices/cpu/events/PM_INST_FROM_L1
+               /sys/devices/cpu/events/PM_IC_DEMAND_REQ
+               /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV_DOUBLE
+               /sys/devices/cpu/events/PM_VSU1_FMA
+               /sys/devices/cpu/events/PM_MRK_LD_MISS_L1
+               /sys/devices/cpu/events/PM_VSU0_2FLOP_DOUBLE
+               /sys/devices/cpu/events/PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_SHR
+               /sys/devices/cpu/events/PM_MRK_LSU_REJECT_ERAT_MISS
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2MISS
+               /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_INST_FROM_PREF
+               /sys/devices/cpu/events/PM_VSU1_SQ
+               /sys/devices/cpu/events/PM_L2_LD_DISP
+               /sys/devices/cpu/events/PM_L2_DISP_ALL
+               /sys/devices/cpu/events/PM_THRD_GRP_CMPL_BOTH_CYC
+               /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV_DOUBLE
+               /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_SHR
+               /sys/devices/cpu/events/PM_VSU_1FLOP
+               /sys/devices/cpu/events/PM_HV_CYC
+               /sys/devices/cpu/events/PM_MRK_LSU_FIN
+               /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR
+               /sys/devices/cpu/events/PM_DTLB_MISS_16M
+               /sys/devices/cpu/events/PM_LSU1_LMQ_LHR_MERGE
+               /sys/devices/cpu/events/PM_IFU_FIN
+               /sys/devices/cpu/events/PM_1THRD_CON_RUN_INSTR
+               /sys/devices/cpu/events/PM_CMPLU_STALL_COUNT
+               /sys/devices/cpu/events/PM_MEM0_PB_RD_CL
+               /sys/devices/cpu/events/PM_THRD_1_RUN_CYC
+               /sys/devices/cpu/events/PM_THRD_2_CONC_RUN_INSTR
+               /sys/devices/cpu/events/PM_THRD_2_RUN_CYC
+               /sys/devices/cpu/events/PM_THRD_3_CONC_RUN_INST
+               /sys/devices/cpu/events/PM_THRD_3_RUN_CYC
+               /sys/devices/cpu/events/PM_THRD_4_CONC_RUN_INST
+               /sys/devices/cpu/events/PM_THRD_4_RUN_CYC
 
 Date:          2013/01/08
 
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
new file mode 100644 (file)
index 0000000..e78ee79
--- /dev/null
@@ -0,0 +1,23 @@
+What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               Provides access to the binary "24x7 catalog" provided by the
+               hypervisor on POWER7 and 8 systems. This catalog lists events
+               avaliable from the powerpc "hv_24x7" pmu. Its format is
+               documented here:
+               https://raw.githubusercontent.com/jmesmon/catalog-24x7/master/hv-24x7-catalog.h
+
+What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog_length
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               A number equal to the length in bytes of the catalog. This is
+               also extractable from the provided binary "catalog" sysfs entry.
+
+What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog_version
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               Exposes the "version" field of the 24x7 catalog. This is also
+               extractable from the provided binary "catalog" sysfs entry.
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
new file mode 100644 (file)
index 0000000..3fa58c2
--- /dev/null
@@ -0,0 +1,43 @@
+What:          /sys/bus/event_source/devices/hv_gpci/interface/collect_privileged
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               '0' if the hypervisor is configured to forbid access to event
+               counters being accumulated by other guests and to physical
+               domain event counters.
+               '1' if that access is allowed.
+
+What:          /sys/bus/event_source/devices/hv_gpci/interface/ga
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               0 or 1. Indicates whether we have access to "GA" events (listed
+               in arch/powerpc/perf/hv-gpci.h).
+
+What:          /sys/bus/event_source/devices/hv_gpci/interface/expanded
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               0 or 1. Indicates whether we have access to "EXPANDED" events (listed
+               in arch/powerpc/perf/hv-gpci.h).
+
+What:          /sys/bus/event_source/devices/hv_gpci/interface/lab
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               0 or 1. Indicates whether we have access to "LAB" events (listed
+               in arch/powerpc/perf/hv-gpci.h).
+
+What:          /sys/bus/event_source/devices/hv_gpci/interface/version
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               A number indicating the version of the gpci interface that the
+               hypervisor reports supporting.
+
+What:          /sys/bus/event_source/devices/hv_gpci/interface/kernel_version
+Date:          February 2014
+Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+               A number indicating the latest version of the gpci interface
+               that the kernel is aware of.
index b2cf5cfb4d29de3dc27e351ba090134bfd624de6..27030d573d8806e6a0108f54d262b1a3cbc2d176 100644 (file)
@@ -5216,11 +5216,10 @@ F:      arch/powerpc/platforms/512x/
 F:     arch/powerpc/platforms/52xx/
 
 LINUX FOR POWERPC EMBEDDED PPC4XX
-M:     Josh Boyer <jwboyer@gmail.com>
+M:  Alistair Popple <alistair@popple.id.au>
 M:     Matt Porter <mporter@kernel.crashing.org>
 W:     http://www.penguinppc.org/
 L:     linuxppc-dev@lists.ozlabs.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
 S:     Maintained
 F:     arch/powerpc/platforms/40x/
 F:     arch/powerpc/platforms/44x/
index e015896b7e5cebacaf46bb713ab16e2fe2128747..f26b267eb71fa947db544f202e6cd55b581b1821 100644 (file)
@@ -73,74 +73,8 @@ CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
 CONFIG_BPF_JIT=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
index f627fda0895303061ee4fc199641fbc6a2a7272b..438e813dc9cb1c18cf4605f5d937135100d39530 100644 (file)
@@ -48,74 +48,8 @@ CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
index e9a8b4e0a0f6309fb7a8a037d01615dc1018ffa1..9ea8342bd219b8851cbe209420b554f9f8128d15 100644 (file)
@@ -65,57 +65,8 @@ CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
@@ -353,3 +304,5 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
index 62771e0adb7cf39d5dde893e43b280b5d07265ec..3c84f9d879800f47ada749fdad0628cfe7bd5be0 100644 (file)
@@ -67,57 +67,8 @@ CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
index a613d2c82fd9e7cbb024a28f493c0be54748d7e0..b142b8e0ed9e26795215248c25aa90d45bf0704c 100644 (file)
@@ -8,7 +8,11 @@
 #include <linux/sched.h>
 
 #define COMPAT_USER_HZ         100
+#ifdef __BIG_ENDIAN__
 #define COMPAT_UTS_MACHINE     "ppc\0\0"
+#else
+#define COMPAT_UTS_MACHINE     "ppcle\0\0"
+#endif
 
 typedef u32            compat_size_t;
 typedef s32            compat_ssize_t;
index 617cc767c07681b109c5acd54f667cc3274956b5..bc2347774f0ad4ed111a5c98546fb763de6d8bbd 100644 (file)
@@ -189,6 +189,7 @@ extern const char *powerpc_base_platform;
 #define        CPU_FTR_HAS_PPR                 LONG_ASM_CONST(0x0200000000000000)
 #define CPU_FTR_DAWR                   LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_DABRX                  LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_PMAO_BUG               LONG_ASM_CONST(0x1000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -445,6 +446,7 @@ extern const char *powerpc_base_platform;
            CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
            CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
            CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP)
+#define CPU_FTRS_POWER8E (CPU_FTRS_POWER8 | CPU_FTR_PMAO_BUG)
 #define CPU_FTRS_CELL  (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -466,8 +468,8 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_POSSIBLE      \
            (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |        \
            CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 |       \
-           CPU_FTRS_POWER7 | CPU_FTRS_POWER8 | CPU_FTRS_CELL |         \
-           CPU_FTRS_PA6T | CPU_FTR_VSX)
+           CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 |      \
+           CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_VSX)
 #endif
 #else
 enum {
index 66830618cc19b2f4b12a5b6cefa8d1663425187e..aeaa56cd9b5465100b00025c7a1da36b3d58e1c5 100644 (file)
@@ -146,6 +146,14 @@ BEGIN_FTR_SECTION_NESTED(943)                                              \
        mfspr   ra,spr;                                                 \
 END_FTR_SECTION_NESTED(ftr,ftr,943)
 
+/*
+ * Set an SPR from a register if the CPU has the given feature
+ */
+#define OPT_SET_SPR(ra, spr, ftr)                                      \
+BEGIN_FTR_SECTION_NESTED(943)                                          \
+       mtspr   spr,ra;                                                 \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
 /*
  * Save a register to the PACA if the CPU has the given feature
  */
index d8b600b3f058bda7e0358931b885b8c5d4f30215..5dbbb29f5c3e554632dd4d361a96fd4a6051a012 100644 (file)
 /* Platform specific hcalls, used by KVM */
 #define H_RTAS                 0xf000
 
+/* "Platform specific hcalls", provided by PHYP */
+#define H_GET_24X7_CATALOG_PAGE        0xF078
+#define H_GET_24X7_DATA                0xF07C
+#define H_GET_PERF_COUNTER_INFO        0xF080
+
 #ifndef __ASSEMBLY__
 
 /**
index 2636acfcd3407515e6bdd331845e1cc5208dda6a..ffafab037ba860b5eaada654528a8bb9332ee338 100644 (file)
@@ -83,6 +83,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #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
@@ -165,8 +167,11 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_DUMP_ACK                          84
 #define OPAL_GET_MSG                           85
 #define OPAL_CHECK_ASYNC_COMPLETION            86
-#define OPAL_DUMP_RESEND                       91
 #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,7 +258,9 @@ enum OpalPendingState {
 };
 
 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,
@@ -406,6 +413,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;
@@ -855,6 +869,12 @@ 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);
@@ -880,6 +900,13 @@ extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
 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;
@@ -890,6 +917,7 @@ 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);
index 3fd2f1b6f90617cf76b9e842e1093bc0db8d70ef..9ed737146dbb3cf5f2253697cbdc96ab8fb07077 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <uapi/asm/perf_event.h>
 
+/* Update perf_event_print_debug() if this changes */
 #define MAX_HWEVENTS           8
 #define MAX_EVENT_ALTERNATIVES 8
 #define MAX_LIMITED_HWCOUNTERS 2
index f7251c2dc0498f7c9a4f6532f18f05b133257d02..1a36b8ede41736f91b305eeb3b1f3c1ac225abcd 100644 (file)
 #define   MMCR0_PMXE   0x04000000UL /* performance monitor exception enable */
 #define   MMCR0_FCECE  0x02000000UL /* freeze ctrs on enabled cond or event */
 #define   MMCR0_TBEE   0x00400000UL /* time base exception enable */
+#define   MMCR0_BHRBA  0x00200000UL /* BHRB Access allowed in userspace */
 #define   MMCR0_EBE    0x00100000UL /* Event based branch enable */
 #define   MMCR0_PMCC   0x000c0000UL /* PMC control */
 #define   MMCR0_PMCC_U6        0x00080000UL /* PMC1-6 are R/W by user (PR) */
 #define   MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
 #define   MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/
 #define   MMCR0_TRIGGER        0x00002000UL /* TRIGGER enable */
+#define   MMCR0_PMAO_SYNC 0x00000800UL /* PMU interrupt is synchronous */
 #define   MMCR0_PMAO   0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */
 #define   MMCR0_SHRFC  0x00000040UL /* SHRre freeze conditions between threads */
 #define   MMCR0_FC56   0x00000010UL /* freeze counters 5 and 6 */
 #define SPRN_EBBHR     804     /* Event based branch handler register */
 #define SPRN_EBBRR     805     /* Event based branch return register */
 #define SPRN_BESCR     806     /* Branch event status and control register */
+#define   BESCR_GE     0x8000000000000000ULL /* Global Enable */
 #define SPRN_WORT      895     /* Workload optimization register - thread */
 
 #define SPRN_PMC1      787
index 6c8dd5da4de5ea0b8b88196b773d2e39fca1c732..c1faade6506dd581e3baf2aebfd93c7972fbd6dc 100644 (file)
@@ -510,7 +510,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x004b0000,
                .cpu_name               = "POWER8E (raw)",
-               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_features           = CPU_FTRS_POWER8E,
                .cpu_user_features      = COMMON_USER_POWER8,
                .cpu_user_features2     = COMMON_USER2_POWER8,
                .mmu_features           = MMU_FTRS_POWER8,
index 38d507306a111dc40f06028c90d5014e2fedd817..4c34c3c827ad5be65a4f59381c9f485086662fe9 100644 (file)
@@ -164,13 +164,18 @@ BEGIN_FTR_SECTION
         */
        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 4cf674d7d5ae184b14c0c4e08985dfe1ad4779a1..f386296ff3785cbf907e9311be50b87a046f45fd 100644 (file)
@@ -1013,12 +1013,13 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
        return NULL;
 }
 
+/* We assume to be passed big endian arguments */
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
        struct rtas_args args;
        unsigned long flags;
        char *buff_copy, *errbuf = NULL;
-       int nargs;
+       int nargs, nret, token;
        int rc;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -1027,10 +1028,13 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
                return -EFAULT;
 
-       nargs = args.nargs;
+       nargs = be32_to_cpu(args.nargs);
+       nret  = be32_to_cpu(args.nret);
+       token = be32_to_cpu(args.token);
+
        if (nargs > ARRAY_SIZE(args.args)
-           || args.nret > ARRAY_SIZE(args.args)
-           || nargs + args.nret > ARRAY_SIZE(args.args))
+           || nret > ARRAY_SIZE(args.args)
+           || nargs + nret > ARRAY_SIZE(args.args))
                return -EINVAL;
 
        /* Copy in args. */
@@ -1038,14 +1042,14 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
                           nargs * sizeof(rtas_arg_t)) != 0)
                return -EFAULT;
 
-       if (args.token == RTAS_UNKNOWN_SERVICE)
+       if (token == RTAS_UNKNOWN_SERVICE)
                return -EINVAL;
 
        args.rets = &args.args[nargs];
-       memset(args.rets, 0, args.nret * sizeof(rtas_arg_t));
+       memset(args.rets, 0, nret * sizeof(rtas_arg_t));
 
        /* Need to handle ibm,suspend_me call specially */
-       if (args.token == ibm_suspend_me_token) {
+       if (token == ibm_suspend_me_token) {
                rc = rtas_ibm_suspend_me(&args);
                if (rc)
                        return rc;
@@ -1062,7 +1066,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 
        /* A -1 return code indicates that the last command couldn't
           be completed due to a hardware error. */
-       if (args.rets[0] == -1)
+       if (be32_to_cpu(args.rets[0]) == -1)
                errbuf = __fetch_rtas_last_error(buff_copy);
 
        unlock_rtas(flags);
@@ -1077,7 +1081,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        /* Copy out args. */
        if (copy_to_user(uargs->args + nargs,
                         args.args + nargs,
-                        args.nret * sizeof(rtas_arg_t)) != 0)
+                        nret * sizeof(rtas_arg_t)) != 0)
                return -EFAULT;
 
        return 0;
index 33cd7a0b8e730b1d22583ab304821a2d1d203cc2..df86f0ce2d360340593548c61e1394a652df3d90 100644 (file)
@@ -1379,8 +1379,9 @@ void facility_unavailable_exception(struct pt_regs *regs)
        if (!arch_irq_disabled_regs(regs))
                local_irq_enable();
 
-       pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
-              hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
+       pr_err_ratelimited(
+               "%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
+               hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
 
        if (user_mode(regs)) {
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
index 62bf5e8e78daaaf5051fb6e5727bfd99be81a088..f6ce1f111f5b143fb338274fb90e704013d47648 100644 (file)
@@ -647,6 +647,11 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
                if (old & _PAGE_HASHPTE)
                        hpte_do_hugepage_flush(vma->vm_mm, address, pmdp);
        }
+       /*
+        * This ensures that generic code that rely on IRQ disabling
+        * to prevent a parallel THP split work as expected.
+        */
+       kick_all_cpus_sync();
 }
 
 /*
index 60d71eea919c7f2e64b8d74e6732e4883fa3f61b..f9c083a5652a4c2a99f6b13778d6f84feed9072e 100644 (file)
@@ -11,5 +11,7 @@ obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o
 obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
 obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
 
+obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o
+
 obj-$(CONFIG_PPC64)            += $(obj64-y)
 obj-$(CONFIG_PPC32)            += $(obj32-y)
index 67cf22083f4c2cfd6175c91ce416efb68ae1a6e6..4520c9356b5473bdf5ae880d214bb4076cee2c3d 100644 (file)
@@ -78,6 +78,7 @@ static unsigned int freeze_events_kernel = MMCR0_FCS;
 #define MMCR0_FC56             0
 #define MMCR0_PMAO             0
 #define MMCR0_EBE              0
+#define MMCR0_BHRBA            0
 #define MMCR0_PMCC             0
 #define MMCR0_PMCC_U6          0
 
@@ -120,6 +121,7 @@ static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
 static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
 void power_pmu_flush_branch_stack(void) {}
 static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
+static void pmao_restore_workaround(bool ebb) { }
 #endif /* CONFIG_PPC32 */
 
 static bool regs_use_siar(struct pt_regs *regs)
@@ -502,8 +504,11 @@ static int ebb_event_check(struct perf_event *event)
                if (!leader->attr.pinned || !leader->attr.exclusive)
                        return -EINVAL;
 
-               if (event->attr.inherit || event->attr.sample_period ||
-                   event->attr.enable_on_exec || event->attr.freq)
+               if (event->attr.freq ||
+                   event->attr.inherit ||
+                   event->attr.sample_type ||
+                   event->attr.sample_period ||
+                   event->attr.enable_on_exec)
                        return -EINVAL;
        }
 
@@ -542,13 +547,21 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
        if (!ebb)
                goto out;
 
-       /* Enable EBB and read/write to all 6 PMCs for userspace */
-       mmcr0 |= MMCR0_EBE | MMCR0_PMCC_U6;
+       /* Enable EBB and read/write to all 6 PMCs and BHRB for userspace */
+       mmcr0 |= MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC_U6;
 
-       /* Add any bits from the user reg, FC or PMAO */
+       /*
+        * Add any bits from the user MMCR0, FC or PMAO. This is compatible
+        * with pmao_restore_workaround() because we may add PMAO but we never
+        * clear it here.
+        */
        mmcr0 |= current->thread.mmcr0;
 
-       /* Be careful not to set PMXE if userspace had it cleared */
+       /*
+        * Be careful not to set PMXE if userspace had it cleared. This is also
+        * compatible with pmao_restore_workaround() because it has already
+        * cleared PMXE and we leave PMAO alone.
+        */
        if (!(current->thread.mmcr0 & MMCR0_PMXE))
                mmcr0 &= ~MMCR0_PMXE;
 
@@ -559,13 +572,94 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
 out:
        return mmcr0;
 }
-#endif /* CONFIG_PPC64 */
-
-static void perf_event_interrupt(struct pt_regs *regs);
 
-void perf_event_print_debug(void)
+static void pmao_restore_workaround(bool ebb)
 {
+       unsigned pmcs[6];
+
+       if (!cpu_has_feature(CPU_FTR_PMAO_BUG))
+               return;
+
+       /*
+        * On POWER8E there is a hardware defect which affects the PMU context
+        * switch logic, ie. power_pmu_disable/enable().
+        *
+        * When a counter overflows PMXE is cleared and FC/PMAO is set in MMCR0
+        * by the hardware. Sometime later the actual PMU exception is
+        * delivered.
+        *
+        * If we context switch, or simply disable/enable, the PMU prior to the
+        * exception arriving, the exception will be lost when we clear PMAO.
+        *
+        * When we reenable the PMU, we will write the saved MMCR0 with PMAO
+        * set, and this _should_ generate an exception. However because of the
+        * defect no exception is generated when we write PMAO, and we get
+        * stuck with no counters counting but no exception delivered.
+        *
+        * The workaround is to detect this case and tweak the hardware to
+        * create another pending PMU exception.
+        *
+        * We do that by setting up PMC6 (cycles) for an imminent overflow and
+        * enabling the PMU. That causes a new exception to be generated in the
+        * chip, but we don't take it yet because we have interrupts hard
+        * disabled. We then write back the PMU state as we want it to be seen
+        * by the exception handler. When we reenable interrupts the exception
+        * handler will be called and see the correct state.
+        *
+        * The logic is the same for EBB, except that the exception is gated by
+        * us having interrupts hard disabled as well as the fact that we are
+        * not in userspace. The exception is finally delivered when we return
+        * to userspace.
+        */
+
+       /* Only if PMAO is set and PMAO_SYNC is clear */
+       if ((current->thread.mmcr0 & (MMCR0_PMAO | MMCR0_PMAO_SYNC)) != MMCR0_PMAO)
+               return;
+
+       /* If we're doing EBB, only if BESCR[GE] is set */
+       if (ebb && !(current->thread.bescr & BESCR_GE))
+               return;
+
+       /*
+        * We are already soft-disabled in power_pmu_enable(). We need to hard
+        * enable to actually prevent the PMU exception from firing.
+        */
+       hard_irq_disable();
+
+       /*
+        * This is a bit gross, but we know we're on POWER8E and have 6 PMCs.
+        * Using read/write_pmc() in a for loop adds 12 function calls and
+        * almost doubles our code size.
+        */
+       pmcs[0] = mfspr(SPRN_PMC1);
+       pmcs[1] = mfspr(SPRN_PMC2);
+       pmcs[2] = mfspr(SPRN_PMC3);
+       pmcs[3] = mfspr(SPRN_PMC4);
+       pmcs[4] = mfspr(SPRN_PMC5);
+       pmcs[5] = mfspr(SPRN_PMC6);
+
+       /* Ensure all freeze bits are unset */
+       mtspr(SPRN_MMCR2, 0);
+
+       /* Set up PMC6 to overflow in one cycle */
+       mtspr(SPRN_PMC6, 0x7FFFFFFE);
+
+       /* Enable exceptions and unfreeze PMC6 */
+       mtspr(SPRN_MMCR0, MMCR0_PMXE | MMCR0_PMCjCE | MMCR0_PMAO);
+
+       /* Now we need to refreeze and restore the PMCs */
+       mtspr(SPRN_MMCR0, MMCR0_FC | MMCR0_PMAO);
+
+       mtspr(SPRN_PMC1, pmcs[0]);
+       mtspr(SPRN_PMC2, pmcs[1]);
+       mtspr(SPRN_PMC3, pmcs[2]);
+       mtspr(SPRN_PMC4, pmcs[3]);
+       mtspr(SPRN_PMC5, pmcs[4]);
+       mtspr(SPRN_PMC6, pmcs[5]);
 }
+#endif /* CONFIG_PPC64 */
+
+static void perf_event_interrupt(struct pt_regs *regs);
 
 /*
  * Read one performance monitor counter (PMC).
@@ -645,6 +739,57 @@ static void write_pmc(int idx, unsigned long val)
        }
 }
 
+/* Called from sysrq_handle_showregs() */
+void perf_event_print_debug(void)
+{
+       unsigned long sdar, sier, flags;
+       u32 pmcs[MAX_HWEVENTS];
+       int i;
+
+       if (!ppmu->n_counter)
+               return;
+
+       local_irq_save(flags);
+
+       pr_info("CPU: %d PMU registers, ppmu = %s n_counters = %d",
+                smp_processor_id(), ppmu->name, ppmu->n_counter);
+
+       for (i = 0; i < ppmu->n_counter; i++)
+               pmcs[i] = read_pmc(i + 1);
+
+       for (; i < MAX_HWEVENTS; i++)
+               pmcs[i] = 0xdeadbeef;
+
+       pr_info("PMC1:  %08x PMC2: %08x PMC3: %08x PMC4: %08x\n",
+                pmcs[0], pmcs[1], pmcs[2], pmcs[3]);
+
+       if (ppmu->n_counter > 4)
+               pr_info("PMC5:  %08x PMC6: %08x PMC7: %08x PMC8: %08x\n",
+                        pmcs[4], pmcs[5], pmcs[6], pmcs[7]);
+
+       pr_info("MMCR0: %016lx MMCR1: %016lx MMCRA: %016lx\n",
+               mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCRA));
+
+       sdar = sier = 0;
+#ifdef CONFIG_PPC64
+       sdar = mfspr(SPRN_SDAR);
+
+       if (ppmu->flags & PPMU_HAS_SIER)
+               sier = mfspr(SPRN_SIER);
+
+       if (ppmu->flags & PPMU_EBB) {
+               pr_info("MMCR2: %016lx EBBHR: %016lx\n",
+                       mfspr(SPRN_MMCR2), mfspr(SPRN_EBBHR));
+               pr_info("EBBRR: %016lx BESCR: %016lx\n",
+                       mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
+       }
+#endif
+       pr_info("SIAR:  %016lx SDAR:  %016lx SIER:  %016lx\n",
+               mfspr(SPRN_SIAR), sdar, sier);
+
+       local_irq_restore(flags);
+}
+
 /*
  * Check if a set of events can all go on the PMU at once.
  * If they can't, this will look at alternative codes for the events
@@ -973,11 +1118,12 @@ static void power_pmu_disable(struct pmu *pmu)
                }
 
                /*
-                * Set the 'freeze counters' bit, clear EBE/PMCC/PMAO/FC56.
+                * Set the 'freeze counters' bit, clear EBE/BHRBA/PMCC/PMAO/FC56
                 */
                val  = mmcr0 = mfspr(SPRN_MMCR0);
                val |= MMCR0_FC;
-               val &= ~(MMCR0_EBE | MMCR0_PMCC | MMCR0_PMAO | MMCR0_FC56);
+               val &= ~(MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC | MMCR0_PMAO |
+                        MMCR0_FC56);
 
                /*
                 * The barrier is to make sure the mtspr has been
@@ -1144,6 +1290,8 @@ static void power_pmu_enable(struct pmu *pmu)
        cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
 
  out_enable:
+       pmao_restore_workaround(ebb);
+
        mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
 
        mb();
diff --git a/arch/powerpc/perf/hv-24x7-catalog.h b/arch/powerpc/perf/hv-24x7-catalog.h
new file mode 100644 (file)
index 0000000..21b19dd
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+#define LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+
+#include <linux/types.h>
+
+/* From document "24x7 Event and Group Catalog Formats Proposal" v0.15 */
+
+struct hv_24x7_catalog_page_0 {
+#define HV_24X7_CATALOG_MAGIC 0x32347837 /* "24x7" in ASCII */
+       __be32 magic;
+       __be32 length; /* In 4096 byte pages */
+       __be64 version; /* XXX: arbitrary? what's the meaning/useage/purpose? */
+       __u8 build_time_stamp[16]; /* "YYYYMMDDHHMMSS\0\0" */
+       __u8 reserved2[32];
+       __be16 schema_data_offs; /* in 4096 byte pages */
+       __be16 schema_data_len;  /* in 4096 byte pages */
+       __be16 schema_entry_count;
+       __u8 reserved3[2];
+       __be16 event_data_offs;
+       __be16 event_data_len;
+       __be16 event_entry_count;
+       __u8 reserved4[2];
+       __be16 group_data_offs; /* in 4096 byte pages */
+       __be16 group_data_len;  /* in 4096 byte pages */
+       __be16 group_entry_count;
+       __u8 reserved5[2];
+       __be16 formula_data_offs; /* in 4096 byte pages */
+       __be16 formula_data_len;  /* in 4096 byte pages */
+       __be16 formula_entry_count;
+       __u8 reserved6[2];
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
new file mode 100644 (file)
index 0000000..297c910
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Hypervisor supplied "24x7" performance counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-24x7: " fmt
+
+#include <linux/perf_event.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-24x7.h"
+#include "hv-24x7-catalog.h"
+#include "hv-common.h"
+
+/*
+ * TODO: Merging events:
+ * - Think of the hcall as an interface to a 4d array of counters:
+ *   - x = domains
+ *   - y = indexes in the domain (core, chip, vcpu, node, etc)
+ *   - z = offset into the counter space
+ *   - w = lpars (guest vms, "logical partitions")
+ * - A single request is: x,y,y_last,z,z_last,w,w_last
+ *   - this means we can retrieve a rectangle of counters in y,z for a single x.
+ *
+ * - Things to consider (ignoring w):
+ *   - input  cost_per_request = 16
+ *   - output cost_per_result(ys,zs)  = 8 + 8 * ys + ys * zs
+ *   - limited number of requests per hcall (must fit into 4K bytes)
+ *     - 4k = 16 [buffer header] - 16 [request size] * request_count
+ *     - 255 requests per hcall
+ *   - sometimes it will be more efficient to read extra data and discard
+ */
+
+/*
+ * Example usage:
+ *  perf stat -e 'hv_24x7/domain=2,offset=8,starting_index=0,lpar=0xffffffff/'
+ */
+
+/* u3 0-6, one of HV_24X7_PERF_DOMAIN */
+EVENT_DEFINE_RANGE_FORMAT(domain, config, 0, 3);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 16, 31);
+/* u32, see "data_offset" */
+EVENT_DEFINE_RANGE_FORMAT(offset, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(lpar, config1, 0, 15);
+
+EVENT_DEFINE_RANGE(reserved1, config,   4, 15);
+EVENT_DEFINE_RANGE(reserved2, config1, 16, 63);
+EVENT_DEFINE_RANGE(reserved3, config2,  0, 63);
+
+static struct attribute *format_attrs[] = {
+       &format_attr_domain.attr,
+       &format_attr_offset.attr,
+       &format_attr_starting_index.attr,
+       &format_attr_lpar.attr,
+       NULL,
+};
+
+static struct attribute_group format_group = {
+       .name = "format",
+       .attrs = format_attrs,
+};
+
+static struct kmem_cache *hv_page_cache;
+
+/*
+ * read_offset_data - copy data from one buffer to another while treating the
+ *                    source buffer as a small view on the total avaliable
+ *                    source data.
+ *
+ * @dest: buffer to copy into
+ * @dest_len: length of @dest in bytes
+ * @requested_offset: the offset within the source data we want. Must be > 0
+ * @src: buffer to copy data from
+ * @src_len: length of @src in bytes
+ * @source_offset: the offset in the sorce data that (src,src_len) refers to.
+ *                 Must be > 0
+ *
+ * returns the number of bytes copied.
+ *
+ * The following ascii art shows the various buffer possitioning we need to
+ * handle, assigns some arbitrary varibles to points on the buffer, and then
+ * shows how we fiddle with those values to get things we care about (copy
+ * start in src and copy len)
+ *
+ * s = @src buffer
+ * d = @dest buffer
+ * '.' areas in d are written to.
+ *
+ *                       u
+ *   x         w        v  z
+ * d           |.........|
+ * s |----------------------|
+ *
+ *                      u
+ *   x         w       z     v
+ * d           |........------|
+ * s |------------------|
+ *
+ *   x         w        u,z,v
+ * d           |........|
+ * s |------------------|
+ *
+ *   x,w                u,v,z
+ * d |..................|
+ * s |------------------|
+ *
+ *   x        u
+ *   w        v                z
+ * d |........|
+ * s |------------------|
+ *
+ *   x      z   w      v
+ * d            |------|
+ * s |------|
+ *
+ * x = source_offset
+ * w = requested_offset
+ * z = source_offset + src_len
+ * v = requested_offset + dest_len
+ *
+ * w_offset_in_s = w - x = requested_offset - source_offset
+ * z_offset_in_s = z - x = src_len
+ * v_offset_in_s = v - x = request_offset + dest_len - src_len
+ */
+static ssize_t read_offset_data(void *dest, size_t dest_len,
+                               loff_t requested_offset, void *src,
+                               size_t src_len, loff_t source_offset)
+{
+       size_t w_offset_in_s = requested_offset - source_offset;
+       size_t z_offset_in_s = src_len;
+       size_t v_offset_in_s = requested_offset + dest_len - src_len;
+       size_t u_offset_in_s = min(z_offset_in_s, v_offset_in_s);
+       size_t copy_len = u_offset_in_s - w_offset_in_s;
+
+       if (requested_offset < 0 || source_offset < 0)
+               return -EINVAL;
+
+       if (z_offset_in_s <= w_offset_in_s)
+               return 0;
+
+       memcpy(dest, src + w_offset_in_s, copy_len);
+       return copy_len;
+}
+
+static unsigned long h_get_24x7_catalog_page(char page[static 4096],
+                                            u32 version, u32 index)
+{
+       WARN_ON(!IS_ALIGNED((unsigned long)page, 4096));
+       return plpar_hcall_norets(H_GET_24X7_CATALOG_PAGE,
+                       virt_to_phys(page),
+                       version,
+                       index);
+}
+
+static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
+                           struct bin_attribute *bin_attr, char *buf,
+                           loff_t offset, size_t count)
+{
+       unsigned long hret;
+       ssize_t ret = 0;
+       size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
+       loff_t page_offset = 0;
+       uint32_t catalog_version_num = 0;
+       void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
+       struct hv_24x7_catalog_page_0 *page_0 = page;
+       if (!page)
+               return -ENOMEM;
+
+       hret = h_get_24x7_catalog_page(page, 0, 0);
+       if (hret) {
+               ret = -EIO;
+               goto e_free;
+       }
+
+       catalog_version_num = be32_to_cpu(page_0->version);
+       catalog_page_len = be32_to_cpu(page_0->length);
+       catalog_len = catalog_page_len * 4096;
+
+       page_offset = offset / 4096;
+       page_count  = count  / 4096;
+
+       if (page_offset >= catalog_page_len)
+               goto e_free;
+
+       if (page_offset != 0) {
+               hret = h_get_24x7_catalog_page(page, catalog_version_num,
+                                              page_offset);
+               if (hret) {
+                       ret = -EIO;
+                       goto e_free;
+               }
+       }
+
+       ret = read_offset_data(buf, count, offset,
+                               page, 4096, page_offset * 4096);
+e_free:
+       if (hret)
+               pr_err("h_get_24x7_catalog_page(ver=%d, page=%lld) failed: rc=%ld\n",
+                               catalog_version_num, page_offset, hret);
+       kfree(page);
+
+       pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
+                       offset, page_offset, count, page_count, catalog_len,
+                       catalog_page_len, ret);
+
+       return ret;
+}
+
+#define PAGE_0_ATTR(_name, _fmt, _expr)                                \
+static ssize_t _name##_show(struct device *dev,                        \
+                           struct device_attribute *dev_attr,  \
+                           char *buf)                          \
+{                                                              \
+       unsigned long hret;                                     \
+       ssize_t ret = 0;                                        \
+       void *page = kmem_cache_alloc(hv_page_cache, GFP_USER); \
+       struct hv_24x7_catalog_page_0 *page_0 = page;           \
+       if (!page)                                              \
+               return -ENOMEM;                                 \
+       hret = h_get_24x7_catalog_page(page, 0, 0);             \
+       if (hret) {                                             \
+               ret = -EIO;                                     \
+               goto e_free;                                    \
+       }                                                       \
+       ret = sprintf(buf, _fmt, _expr);                        \
+e_free:                                                                \
+       kfree(page);                                            \
+       return ret;                                             \
+}                                                              \
+static DEVICE_ATTR_RO(_name)
+
+PAGE_0_ATTR(catalog_version, "%lld\n",
+               (unsigned long long)be32_to_cpu(page_0->version));
+PAGE_0_ATTR(catalog_len, "%lld\n",
+               (unsigned long long)be32_to_cpu(page_0->length) * 4096);
+static BIN_ATTR_RO(catalog, 0/* real length varies */);
+
+static struct bin_attribute *if_bin_attrs[] = {
+       &bin_attr_catalog,
+       NULL,
+};
+
+static struct attribute *if_attrs[] = {
+       &dev_attr_catalog_len.attr,
+       &dev_attr_catalog_version.attr,
+       NULL,
+};
+
+static struct attribute_group if_group = {
+       .name = "interface",
+       .bin_attrs = if_bin_attrs,
+       .attrs = if_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+       &format_group,
+       &if_group,
+       NULL,
+};
+
+static bool is_physical_domain(int domain)
+{
+       return  domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP ||
+               domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE;
+}
+
+static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
+                                        u16 lpar, u64 *res,
+                                        bool success_expected)
+{
+       unsigned long ret;
+
+       /*
+        * request_buffer and result_buffer are not required to be 4k aligned,
+        * but are not allowed to cross any 4k boundary. Aligning them to 4k is
+        * the simplest way to ensure that.
+        */
+       struct reqb {
+               struct hv_24x7_request_buffer buf;
+               struct hv_24x7_request req;
+       } __packed __aligned(4096) request_buffer = {
+               .buf = {
+                       .interface_version = HV_24X7_IF_VERSION_CURRENT,
+                       .num_requests = 1,
+               },
+               .req = {
+                       .performance_domain = domain,
+                       .data_size = cpu_to_be16(8),
+                       .data_offset = cpu_to_be32(offset),
+                       .starting_lpar_ix = cpu_to_be16(lpar),
+                       .max_num_lpars = cpu_to_be16(1),
+                       .starting_ix = cpu_to_be16(ix),
+                       .max_ix = cpu_to_be16(1),
+               }
+       };
+
+       struct resb {
+               struct hv_24x7_data_result_buffer buf;
+               struct hv_24x7_result res;
+               struct hv_24x7_result_element elem;
+               __be64 result;
+       } __packed __aligned(4096) result_buffer = {};
+
+       ret = plpar_hcall_norets(H_GET_24X7_DATA,
+                       virt_to_phys(&request_buffer), sizeof(request_buffer),
+                       virt_to_phys(&result_buffer),  sizeof(result_buffer));
+
+       if (ret) {
+               if (success_expected)
+                       pr_err_ratelimited("hcall failed: %d %#x %#x %d => 0x%lx (%ld) detail=0x%x failing ix=%x\n",
+                                       domain, offset, ix, lpar,
+                                       ret, ret,
+                                       result_buffer.buf.detailed_rc,
+                                       result_buffer.buf.failing_request_ix);
+               return ret;
+       }
+
+       *res = be64_to_cpu(result_buffer.result);
+       return ret;
+}
+
+static unsigned long event_24x7_request(struct perf_event *event, u64 *res,
+               bool success_expected)
+{
+       return single_24x7_request(event_get_domain(event),
+                               event_get_offset(event),
+                               event_get_starting_index(event),
+                               event_get_lpar(event),
+                               res,
+                               success_expected);
+}
+
+static int h_24x7_event_init(struct perf_event *event)
+{
+       struct hv_perf_caps caps;
+       unsigned domain;
+       unsigned long hret;
+       u64 ct;
+
+       /* Not our event */
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       /* Unused areas must be 0 */
+       if (event_get_reserved1(event) ||
+           event_get_reserved2(event) ||
+           event_get_reserved3(event)) {
+               pr_devel("reserved set when forbidden 0x%llx(0x%llx) 0x%llx(0x%llx) 0x%llx(0x%llx)\n",
+                               event->attr.config,
+                               event_get_reserved1(event),
+                               event->attr.config1,
+                               event_get_reserved2(event),
+                               event->attr.config2,
+                               event_get_reserved3(event));
+               return -EINVAL;
+       }
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           is_sampling_event(event)) /* no sampling */
+               return -EINVAL;
+
+       /* no branch sampling */
+       if (has_branch_stack(event))
+               return -EOPNOTSUPP;
+
+       /* offset must be 8 byte aligned */
+       if (event_get_offset(event) % 8) {
+               pr_devel("bad alignment\n");
+               return -EINVAL;
+       }
+
+       /* Domains above 6 are invalid */
+       domain = event_get_domain(event);
+       if (domain > 6) {
+               pr_devel("invalid domain %d\n", domain);
+               return -EINVAL;
+       }
+
+       hret = hv_perf_caps_get(&caps);
+       if (hret) {
+               pr_devel("could not get capabilities: rc=%ld\n", hret);
+               return -EIO;
+       }
+
+       /* PHYSICAL domains & other lpars require extra capabilities */
+       if (!caps.collect_privileged && (is_physical_domain(domain) ||
+               (event_get_lpar(event) != event_get_lpar_max()))) {
+               pr_devel("hv permisions disallow: is_physical_domain:%d, lpar=0x%llx\n",
+                               is_physical_domain(domain),
+                               event_get_lpar(event));
+               return -EACCES;
+       }
+
+       /* see if the event complains */
+       if (event_24x7_request(event, &ct, false)) {
+               pr_devel("test hcall failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static u64 h_24x7_get_value(struct perf_event *event)
+{
+       unsigned long ret;
+       u64 ct;
+       ret = event_24x7_request(event, &ct, true);
+       if (ret)
+               /* We checked this in event init, shouldn't fail here... */
+               return 0;
+
+       return ct;
+}
+
+static void h_24x7_event_update(struct perf_event *event)
+{
+       s64 prev;
+       u64 now;
+       now = h_24x7_get_value(event);
+       prev = local64_xchg(&event->hw.prev_count, now);
+       local64_add(now - prev, &event->count);
+}
+
+static void h_24x7_event_start(struct perf_event *event, int flags)
+{
+       if (flags & PERF_EF_RELOAD)
+               local64_set(&event->hw.prev_count, h_24x7_get_value(event));
+}
+
+static void h_24x7_event_stop(struct perf_event *event, int flags)
+{
+       h_24x7_event_update(event);
+}
+
+static int h_24x7_event_add(struct perf_event *event, int flags)
+{
+       if (flags & PERF_EF_START)
+               h_24x7_event_start(event, flags);
+
+       return 0;
+}
+
+static int h_24x7_event_idx(struct perf_event *event)
+{
+       return 0;
+}
+
+static struct pmu h_24x7_pmu = {
+       .task_ctx_nr = perf_invalid_context,
+
+       .name = "hv_24x7",
+       .attr_groups = attr_groups,
+       .event_init  = h_24x7_event_init,
+       .add         = h_24x7_event_add,
+       .del         = h_24x7_event_stop,
+       .start       = h_24x7_event_start,
+       .stop        = h_24x7_event_stop,
+       .read        = h_24x7_event_update,
+       .event_idx   = h_24x7_event_idx,
+};
+
+static int hv_24x7_init(void)
+{
+       int r;
+       unsigned long hret;
+       struct hv_perf_caps caps;
+
+       if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+               pr_info("not a virtualized system, not enabling\n");
+               return -ENODEV;
+       }
+
+       hret = hv_perf_caps_get(&caps);
+       if (hret) {
+               pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+                               hret);
+               return -ENODEV;
+       }
+
+       hv_page_cache = kmem_cache_create("hv-page-4096", 4096, 4096, 0, NULL);
+       if (!hv_page_cache)
+               return -ENOMEM;
+
+       r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+device_initcall(hv_24x7_init);
diff --git a/arch/powerpc/perf/hv-24x7.h b/arch/powerpc/perf/hv-24x7.h
new file mode 100644 (file)
index 0000000..720ebce
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_H_
+#define LINUX_POWERPC_PERF_HV_24X7_H_
+
+#include <linux/types.h>
+
+struct hv_24x7_request {
+       /* PHYSICAL domains require enabling via phyp/hmc. */
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP 0x01
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CORE 0x02
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CORE   0x03
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CHIP   0x04
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_NODE   0x05
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_REMOTE_NODE 0x06
+       __u8 performance_domain;
+       __u8 reserved[0x1];
+
+       /* bytes to read starting at @data_offset. must be a multiple of 8 */
+       __be16 data_size;
+
+       /*
+        * byte offset within the perf domain to read from. must be 8 byte
+        * aligned
+        */
+       __be32 data_offset;
+
+       /*
+        * only valid for VIRTUAL_PROCESSOR domains, ignored for others.
+        * -1 means "current partition only"
+        *  Enabling via phyp/hmc required for non-"-1" values. 0 forbidden
+        *  unless requestor is 0.
+        */
+       __be16 starting_lpar_ix;
+
+       /*
+        * Ignored when @starting_lpar_ix == -1
+        * Ignored when @performance_domain is not VIRTUAL_PROCESSOR_*
+        * -1 means "infinite" or all
+        */
+       __be16 max_num_lpars;
+
+       /* chip, core, or virtual processor based on @performance_domain */
+       __be16 starting_ix;
+       __be16 max_ix;
+} __packed;
+
+struct hv_24x7_request_buffer {
+       /* 0 - ? */
+       /* 1 - ? */
+#define HV_24X7_IF_VERSION_CURRENT 0x01
+       __u8 interface_version;
+       __u8 num_requests;
+       __u8 reserved[0xE];
+       struct hv_24x7_request requests[];
+} __packed;
+
+struct hv_24x7_result_element {
+       __be16 lpar_ix;
+
+       /*
+        * represents the core, chip, or virtual processor based on the
+        * request's @performance_domain
+        */
+       __be16 domain_ix;
+
+       /* -1 if @performance_domain does not refer to a virtual processor */
+       __be32 lpar_cfg_instance_id;
+
+       /* size = @result_element_data_size of cointaining result. */
+       __u8 element_data[];
+} __packed;
+
+struct hv_24x7_result {
+       __u8 result_ix;
+
+       /*
+        * 0 = not all result elements fit into the buffer, additional requests
+        *     required
+        * 1 = all result elements were returned
+        */
+       __u8 results_complete;
+       __be16 num_elements_returned;
+
+       /* This is a copy of @data_size from the coresponding hv_24x7_request */
+       __be16 result_element_data_size;
+       __u8 reserved[0x2];
+
+       /* WARNING: only valid for first result element due to variable sizes
+        *          of result elements */
+       /* struct hv_24x7_result_element[@num_elements_returned] */
+       struct hv_24x7_result_element elements[];
+} __packed;
+
+struct hv_24x7_data_result_buffer {
+       /* See versioning for request buffer */
+       __u8 interface_version;
+
+       __u8 num_results;
+       __u8 reserved[0x1];
+       __u8 failing_request_ix;
+       __be32 detailed_rc;
+       __be64 cec_cfg_instance_id;
+       __be64 catalog_version_num;
+       __u8 reserved2[0x8];
+       /* WARNING: only valid for the first result due to variable sizes of
+        *          results */
+       struct hv_24x7_result results[]; /* [@num_results] */
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-common.c b/arch/powerpc/perf/hv-common.c
new file mode 100644 (file)
index 0000000..47e02b3
--- /dev/null
@@ -0,0 +1,39 @@
+#include <asm/io.h>
+#include <asm/hvcall.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
+{
+       unsigned long r;
+       struct p {
+               struct hv_get_perf_counter_info_params params;
+               struct cv_system_performance_capabilities caps;
+       } __packed __aligned(sizeof(uint64_t));
+
+       struct p arg = {
+               .params = {
+                       .counter_request = cpu_to_be32(
+                                       CIR_SYSTEM_PERFORMANCE_CAPABILITIES),
+                       .starting_index = cpu_to_be32(-1),
+                       .counter_info_version_in = 0,
+               }
+       };
+
+       r = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+                              virt_to_phys(&arg), sizeof(arg));
+
+       if (r)
+               return r;
+
+       pr_devel("capability_mask: 0x%x\n", arg.caps.capability_mask);
+
+       caps->version = arg.params.counter_info_version_out;
+       caps->collect_privileged = !!arg.caps.perf_collect_privileged;
+       caps->ga = !!(arg.caps.capability_mask & CV_CM_GA);
+       caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED);
+       caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB);
+
+       return r;
+}
diff --git a/arch/powerpc/perf/hv-common.h b/arch/powerpc/perf/hv-common.h
new file mode 100644 (file)
index 0000000..5d79cec
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef LINUX_POWERPC_PERF_HV_COMMON_H_
+#define LINUX_POWERPC_PERF_HV_COMMON_H_
+
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+struct hv_perf_caps {
+       u16 version;
+       u16 collect_privileged:1,
+           ga:1,
+           expanded:1,
+           lab:1,
+           unused:12;
+};
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps);
+
+
+#define EVENT_DEFINE_RANGE_FORMAT(name, attr_var, bit_start, bit_end)  \
+PMU_FORMAT_ATTR(name, #attr_var ":" #bit_start "-" #bit_end);          \
+EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end)
+
+#define EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end) \
+static u64 event_get_##name##_max(void)                                        \
+{                                                                      \
+       BUILD_BUG_ON((bit_start > bit_end)                              \
+                   || (bit_end >= (sizeof(1ull) * 8)));                \
+       return (((1ull << (bit_end - bit_start)) - 1) << 1) + 1;        \
+}                                                                      \
+static u64 event_get_##name(struct perf_event *event)                  \
+{                                                                      \
+       return (event->attr.attr_var >> (bit_start)) &                  \
+               event_get_##name##_max();                               \
+}
+
+#endif
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
new file mode 100644 (file)
index 0000000..278ba7b
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Hypervisor supplied "gpci" ("get performance counter info") performance
+ * counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-gpci: " fmt
+
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+/*
+ * Example usage:
+ *  perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
+ *               secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
+ */
+
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
+/* u8 */
+EVENT_DEFINE_RANGE_FORMAT(counter_info_version, config1, 16, 23);
+/* u8, bytes of data (1-8) */
+EVENT_DEFINE_RANGE_FORMAT(length, config1, 24, 31);
+/* u32, byte offset */
+EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
+
+static struct attribute *format_attrs[] = {
+       &format_attr_request.attr,
+       &format_attr_starting_index.attr,
+       &format_attr_secondary_index.attr,
+       &format_attr_counter_info_version.attr,
+
+       &format_attr_offset.attr,
+       &format_attr_length.attr,
+       NULL,
+};
+
+static struct attribute_group format_group = {
+       .name = "format",
+       .attrs = format_attrs,
+};
+
+#define HV_CAPS_ATTR(_name, _format)                           \
+static ssize_t _name##_show(struct device *dev,                        \
+                           struct device_attribute *attr,      \
+                           char *page)                         \
+{                                                              \
+       struct hv_perf_caps caps;                               \
+       unsigned long hret = hv_perf_caps_get(&caps);           \
+       if (hret)                                               \
+               return -EIO;                                    \
+                                                               \
+       return sprintf(page, _format, caps._name);              \
+}                                                              \
+static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t kernel_version_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *page)
+{
+       return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
+}
+
+DEVICE_ATTR_RO(kernel_version);
+HV_CAPS_ATTR(version, "0x%x\n");
+HV_CAPS_ATTR(ga, "%d\n");
+HV_CAPS_ATTR(expanded, "%d\n");
+HV_CAPS_ATTR(lab, "%d\n");
+HV_CAPS_ATTR(collect_privileged, "%d\n");
+
+static struct attribute *interface_attrs[] = {
+       &dev_attr_kernel_version.attr,
+       &hv_caps_attr_version.attr,
+       &hv_caps_attr_ga.attr,
+       &hv_caps_attr_expanded.attr,
+       &hv_caps_attr_lab.attr,
+       &hv_caps_attr_collect_privileged.attr,
+       NULL,
+};
+
+static struct attribute_group interface_group = {
+       .name = "interface",
+       .attrs = interface_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+       &format_group,
+       &interface_group,
+       NULL,
+};
+
+#define GPCI_MAX_DATA_BYTES \
+       (1024 - sizeof(struct hv_get_perf_counter_info_params))
+
+static unsigned long single_gpci_request(u32 req, u32 starting_index,
+               u16 secondary_index, u8 version_in, u32 offset, u8 length,
+               u64 *value)
+{
+       unsigned long ret;
+       size_t i;
+       u64 count;
+
+       struct {
+               struct hv_get_perf_counter_info_params params;
+               uint8_t bytes[GPCI_MAX_DATA_BYTES];
+       } __packed __aligned(sizeof(uint64_t)) arg = {
+               .params = {
+                       .counter_request = cpu_to_be32(req),
+                       .starting_index = cpu_to_be32(starting_index),
+                       .secondary_index = cpu_to_be16(secondary_index),
+                       .counter_info_version_in = version_in,
+               }
+       };
+
+       ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+                       virt_to_phys(&arg), sizeof(arg));
+       if (ret) {
+               pr_devel("hcall failed: 0x%lx\n", ret);
+               return ret;
+       }
+
+       /*
+        * we verify offset and length are within the zeroed buffer at event
+        * init.
+        */
+       count = 0;
+       for (i = offset; i < offset + length; i++)
+               count |= arg.bytes[i] << (i - offset);
+
+       *value = count;
+       return ret;
+}
+
+static u64 h_gpci_get_value(struct perf_event *event)
+{
+       u64 count;
+       unsigned long ret = single_gpci_request(event_get_request(event),
+                                       event_get_starting_index(event),
+                                       event_get_secondary_index(event),
+                                       event_get_counter_info_version(event),
+                                       event_get_offset(event),
+                                       event_get_length(event),
+                                       &count);
+       if (ret)
+               return 0;
+       return count;
+}
+
+static void h_gpci_event_update(struct perf_event *event)
+{
+       s64 prev;
+       u64 now = h_gpci_get_value(event);
+       prev = local64_xchg(&event->hw.prev_count, now);
+       local64_add(now - prev, &event->count);
+}
+
+static void h_gpci_event_start(struct perf_event *event, int flags)
+{
+       local64_set(&event->hw.prev_count, h_gpci_get_value(event));
+}
+
+static void h_gpci_event_stop(struct perf_event *event, int flags)
+{
+       h_gpci_event_update(event);
+}
+
+static int h_gpci_event_add(struct perf_event *event, int flags)
+{
+       if (flags & PERF_EF_START)
+               h_gpci_event_start(event, flags);
+
+       return 0;
+}
+
+static int h_gpci_event_init(struct perf_event *event)
+{
+       u64 count;
+       u8 length;
+
+       /* Not our event */
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       /* config2 is unused */
+       if (event->attr.config2) {
+               pr_devel("config2 set when reserved\n");
+               return -EINVAL;
+       }
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           is_sampling_event(event)) /* no sampling */
+               return -EINVAL;
+
+       /* no branch sampling */
+       if (has_branch_stack(event))
+               return -EOPNOTSUPP;
+
+       length = event_get_length(event);
+       if (length < 1 || length > 8) {
+               pr_devel("length invalid\n");
+               return -EINVAL;
+       }
+
+       /* last byte within the buffer? */
+       if ((event_get_offset(event) + length) > GPCI_MAX_DATA_BYTES) {
+               pr_devel("request outside of buffer: %zu > %zu\n",
+                               (size_t)event_get_offset(event) + length,
+                               GPCI_MAX_DATA_BYTES);
+               return -EINVAL;
+       }
+
+       /* check if the request works... */
+       if (single_gpci_request(event_get_request(event),
+                               event_get_starting_index(event),
+                               event_get_secondary_index(event),
+                               event_get_counter_info_version(event),
+                               event_get_offset(event),
+                               length,
+                               &count)) {
+               pr_devel("gpci hcall failed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int h_gpci_event_idx(struct perf_event *event)
+{
+       return 0;
+}
+
+static struct pmu h_gpci_pmu = {
+       .task_ctx_nr = perf_invalid_context,
+
+       .name = "hv_gpci",
+       .attr_groups = attr_groups,
+       .event_init  = h_gpci_event_init,
+       .add         = h_gpci_event_add,
+       .del         = h_gpci_event_stop,
+       .start       = h_gpci_event_start,
+       .stop        = h_gpci_event_stop,
+       .read        = h_gpci_event_update,
+       .event_idx   = h_gpci_event_idx,
+};
+
+static int hv_gpci_init(void)
+{
+       int r;
+       unsigned long hret;
+       struct hv_perf_caps caps;
+
+       if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+               pr_info("not a virtualized system, not enabling\n");
+               return -ENODEV;
+       }
+
+       hret = hv_perf_caps_get(&caps);
+       if (hret) {
+               pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+                               hret);
+               return -ENODEV;
+       }
+
+       r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+device_initcall(hv_gpci_init);
diff --git a/arch/powerpc/perf/hv-gpci.h b/arch/powerpc/perf/hv-gpci.h
new file mode 100644 (file)
index 0000000..b25f460
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef LINUX_POWERPC_PERF_HV_GPCI_H_
+#define LINUX_POWERPC_PERF_HV_GPCI_H_
+
+#include <linux/types.h>
+
+/* From the document "H_GetPerformanceCounterInfo Interface" v1.07 */
+
+/* H_GET_PERF_COUNTER_INFO argument */
+struct hv_get_perf_counter_info_params {
+       __be32 counter_request; /* I */
+       __be32 starting_index;  /* IO */
+       __be16 secondary_index; /* IO */
+       __be16 returned_values; /* O */
+       __be32 detail_rc; /* O, only needed when called via *_norets() */
+
+       /*
+        * O, size each of counter_value element in bytes, only set for version
+        * >= 0x3
+        */
+       __be16 cv_element_size;
+
+       /* I, 0 (zero) for versions < 0x3 */
+       __u8 counter_info_version_in;
+
+       /* O, 0 (zero) if version < 0x3. Must be set to 0 when making hcall */
+       __u8 counter_info_version_out;
+       __u8 reserved[0xC];
+       __u8 counter_value[];
+} __packed;
+
+/*
+ * counter info version => fw version/reference (spec version)
+ *
+ * 8 => power8 (1.07)
+ * [7 is skipped by spec 1.07]
+ * 6 => TLBIE (1.07)
+ * 5 => v7r7m0.phyp (1.05)
+ * [4 skipped]
+ * 3 => v7r6m0.phyp (?)
+ * [1,2 skipped]
+ * 0 => v7r{2,3,4}m0.phyp (?)
+ */
+#define COUNTER_INFO_VERSION_CURRENT 0x8
+
+/*
+ * These determine the counter_value[] layout and the meaning of starting_index
+ * and secondary_index.
+ *
+ * Unless otherwise noted, @secondary_index is unused and ignored.
+ */
+enum counter_info_requests {
+
+       /* GENERAL */
+
+       /* @starting_index: must be -1 (to refer to the current partition)
+        */
+       CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40,
+};
+
+struct cv_system_performance_capabilities {
+       /* If != 0, allowed to collect data from other partitions */
+       __u8 perf_collect_privileged;
+
+       /* These following are only valid if counter_info_version >= 0x3 */
+#define CV_CM_GA       (1 << 7)
+#define CV_CM_EXPANDED (1 << 6)
+#define CV_CM_LAB      (1 << 5)
+       /* remaining bits are reserved */
+       __u8 capability_mask;
+       __u8 reserved[0xE];
+} __packed;
+
+#endif
index 687790a2c0b8dd57025a86a0092277b3b2abda09..64f13d9260a691526caa6fe374a37565b0027d09 100644 (file)
@@ -546,3 +546,13 @@ EVENT(PM_MRK_DATA_FROM_RL2L3_SHR,             0x1d04c)
 EVENT(PM_DTLB_MISS_16M,                       0x4c05e)
 EVENT(PM_LSU1_LMQ_LHR_MERGE,                  0x0d09a)
 EVENT(PM_IFU_FIN,                             0x40066)
+EVENT(PM_1THRD_CON_RUN_INSTR,                 0x30062)
+EVENT(PM_CMPLU_STALL_COUNT,                   0x4000B)
+EVENT(PM_MEM0_PB_RD_CL,                       0x30083)
+EVENT(PM_THRD_1_RUN_CYC,                      0x10060)
+EVENT(PM_THRD_2_CONC_RUN_INSTR,               0x40062)
+EVENT(PM_THRD_2_RUN_CYC,                      0x20060)
+EVENT(PM_THRD_3_CONC_RUN_INST,                0x10062)
+EVENT(PM_THRD_3_RUN_CYC,                      0x30060)
+EVENT(PM_THRD_4_CONC_RUN_INST,                0x20062)
+EVENT(PM_THRD_4_RUN_CYC,                      0x40060)
index 96cee20dcd34ec2cf33f6d836d4f4fd49b7848c6..fe2763b6e039cfc5773ba8255731a3f7d7228d78 100644 (file)
@@ -10,6 +10,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt)    "power8-pmu: " fmt
+
 #include <linux/kernel.h>
 #include <linux/perf_event.h>
 #include <asm/firmware.h>
  *
  *        60        56        52        48        44        40        36        32
  * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- *   |                                 [      thresh_cmp     ]   [  thresh_ctl   ]
- *   |                                                                   |
- *   *- EBB (Linux)                      thresh start/stop OR FAB match -*
+ *   | | [ ]                           [      thresh_cmp     ]   [  thresh_ctl   ]
+ *   | |  |                                                              |
+ *   | |  *- IFM (Linux)                 thresh start/stop OR FAB match -*
+ *   | *- BHRB (Linux)
+ *   *- EBB (Linux)
  *
  *        28        24        20        16        12         8         4         0
  * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
  *     MMCRA[63]    = 1                (SAMPLE_ENABLE)
  *     MMCRA[57:59] = sample[0:2]      (RAND_SAMP_ELIG)
 Â *    MMCRA[61:62] = sample[3:4]      (RAND_SAMP_MODE)
+ *
+ * if EBB and BHRB:
+ *     MMCRA[32:33] = IFM
  *
  */
 
 #define EVENT_EBB_MASK         1ull
+#define EVENT_EBB_SHIFT                PERF_EVENT_CONFIG_EBB_SHIFT
+#define EVENT_BHRB_MASK                1ull
+#define EVENT_BHRB_SHIFT       62
+#define EVENT_WANTS_BHRB       (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT)
+#define EVENT_IFM_MASK         3ull
+#define EVENT_IFM_SHIFT                60
 #define EVENT_THR_CMP_SHIFT    40      /* Threshold CMP value */
 #define EVENT_THR_CMP_MASK     0x3ff
 #define EVENT_THR_CTL_SHIFT    32      /* Threshold control value (start/stop) */
 #define EVENT_IS_MARKED                (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
 #define EVENT_PSEL_MASK                0xff    /* PMCxSEL value */
 
+/* Bits defined by Linux */
+#define EVENT_LINUX_MASK       \
+       ((EVENT_EBB_MASK  << EVENT_EBB_SHIFT)                   |       \
+        (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT)                  |       \
+        (EVENT_IFM_MASK  << EVENT_IFM_SHIFT))
+
 #define EVENT_VALID_MASK       \
        ((EVENT_THRESH_MASK    << EVENT_THRESH_SHIFT)           |       \
         (EVENT_SAMPLE_MASK    << EVENT_SAMPLE_SHIFT)           |       \
         (EVENT_UNIT_MASK      << EVENT_UNIT_SHIFT)             |       \
         (EVENT_COMBINE_MASK   << EVENT_COMBINE_SHIFT)          |       \
         (EVENT_MARKED_MASK    << EVENT_MARKED_SHIFT)           |       \
-        (EVENT_EBB_MASK       << PERF_EVENT_CONFIG_EBB_SHIFT)  |       \
+         EVENT_LINUX_MASK                                      |       \
          EVENT_PSEL_MASK)
 
 /* MMCRA IFM bits - POWER8 */
  *
  *        28        24        20        16        12         8         4         0
  * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- *                   |   [ ]   [  sample ]   [     ]   [6] [5]   [4] [3]   [2] [1]
- *              EBB -*    |                     |
- *                        |                     |      Count of events for each PMC.
- *      L1 I/D qualifier -*                     |        p1, p2, p3, p4, p5, p6.
+ *               [ ] |   [ ]   [  sample ]   [     ]   [6] [5]   [4] [3]   [2] [1]
+ *                |  |    |                     |
+ *      BHRB IFM -*  |    |                     |      Count of events for each PMC.
+ *              EBB -*    |                     |        p1, p2, p3, p4, p5, p6.
+ *      L1 I/D qualifier -*                     |
  *                     nc - number of counters -*
  *
  * The PMC fields P1..P6, and NC, are adder fields. As we accumulate constraints
 #define CNST_EBB_VAL(v)                (((v) & EVENT_EBB_MASK) << 24)
 #define CNST_EBB_MASK          CNST_EBB_VAL(EVENT_EBB_MASK)
 
+#define CNST_IFM_VAL(v)                (((v) & EVENT_IFM_MASK) << 25)
+#define CNST_IFM_MASK          CNST_IFM_VAL(EVENT_IFM_MASK)
+
 #define CNST_L1_QUAL_VAL(v)    (((v) & 3) << 22)
 #define CNST_L1_QUAL_MASK      CNST_L1_QUAL_VAL(3)
 
 #define MMCRA_THR_SEL_SHIFT            16
 #define MMCRA_THR_CMP_SHIFT            32
 #define MMCRA_SDAR_MODE_TLB            (1ull << 42)
+#define MMCRA_IFM_SHIFT                        30
 
 
 static inline bool event_is_fab_match(u64 event)
@@ -265,20 +289,22 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
        pmc   = (event >> EVENT_PMC_SHIFT)        & EVENT_PMC_MASK;
        unit  = (event >> EVENT_UNIT_SHIFT)       & EVENT_UNIT_MASK;
        cache = (event >> EVENT_CACHE_SEL_SHIFT)  & EVENT_CACHE_SEL_MASK;
-       ebb   = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
-
-       /* Clear the EBB bit in the event, so event checks work below */
-       event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
+       ebb   = (event >> EVENT_EBB_SHIFT)        & EVENT_EBB_MASK;
 
        if (pmc) {
+               u64 base_event;
+
                if (pmc > 6)
                        return -1;
 
-               mask  |= CNST_PMC_MASK(pmc);
-               value |= CNST_PMC_VAL(pmc);
+               /* Ignore Linux defined bits when checking event below */
+               base_event = event & ~EVENT_LINUX_MASK;
 
-               if (pmc >= 5 && event != 0x500fa && event != 0x600f4)
+               if (pmc >= 5 && base_event != 0x500fa && base_event != 0x600f4)
                        return -1;
+
+               mask  |= CNST_PMC_MASK(pmc);
+               value |= CNST_PMC_VAL(pmc);
        }
 
        if (pmc <= 4) {
@@ -299,9 +325,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
                 * HV writable, and there is no API for guest kernels to modify
                 * it. The solution is for the hypervisor to initialise the
                 * field to zeroes, and for us to only ever allow events that
-                * have a cache selector of zero.
+                * have a cache selector of zero. The bank selector (bit 3) is
+                * irrelevant, as long as the rest of the value is 0.
                 */
-               if (cache)
+               if (cache & 0x7)
                        return -1;
 
        } else if (event & EVENT_IS_L1) {
@@ -342,6 +369,15 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
                /* EBB events must specify the PMC */
                return -1;
 
+       if (event & EVENT_WANTS_BHRB) {
+               if (!ebb)
+                       /* Only EBB events can request BHRB */
+                       return -1;
+
+               mask  |= CNST_IFM_MASK;
+               value |= CNST_IFM_VAL(event >> EVENT_IFM_SHIFT);
+       }
+
        /*
         * All events must agree on EBB, either all request it or none.
         * EBB events are pinned & exclusive, so this should never actually
@@ -431,6 +467,11 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
                        mmcra |= val << MMCRA_THR_CMP_SHIFT;
                }
 
+               if (event[i] & EVENT_WANTS_BHRB) {
+                       val = (event[i] >> EVENT_IFM_SHIFT) & EVENT_IFM_MASK;
+                       mmcra |= val << MMCRA_IFM_SHIFT;
+               }
+
                hwc[i] = pmc - 1;
        }
 
@@ -774,6 +815,9 @@ static int __init init_power8_pmu(void)
        /* Tell userspace that EBB is supported */
        cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
 
+       if (cpu_has_feature(CPU_FTR_PMAO_BUG))
+               pr_info("PMAO restore workaround active.\n");
+
        return 0;
 }
 early_initcall(init_power8_pmu);
index 5125caeb40f4bef9bfd937d22bb73e45f315781e..f324ea0995033c9197ace32b35a4b50768b7a3ce 100644 (file)
@@ -1,6 +1,6 @@
-obj-y                  += setup.o opal-takeover.o opal-wrappers.o opal.o
+obj-y                  += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
 obj-y                  += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
-obj-y                  += rng.o opal-elog.o opal-dump.o
+obj-y                  += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_PCI)      += pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
new file mode 100644 (file)
index 0000000..cd0c135
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * PowerNV OPAL asynchronous completion interfaces
+ *
+ * Copyright 2013 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <asm/opal.h>
+
+#define N_ASYNC_COMPLETIONS    64
+
+static DECLARE_BITMAP(opal_async_complete_map, N_ASYNC_COMPLETIONS) = {~0UL};
+static DECLARE_BITMAP(opal_async_token_map, N_ASYNC_COMPLETIONS);
+static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
+static DEFINE_SPINLOCK(opal_async_comp_lock);
+static struct semaphore opal_async_sem;
+static struct opal_msg *opal_async_responses;
+static unsigned int opal_max_async_tokens;
+
+int __opal_async_get_token(void)
+{
+       unsigned long flags;
+       int token;
+
+       spin_lock_irqsave(&opal_async_comp_lock, flags);
+       token = find_first_bit(opal_async_complete_map, opal_max_async_tokens);
+       if (token >= opal_max_async_tokens) {
+               token = -EBUSY;
+               goto out;
+       }
+
+       if (__test_and_set_bit(token, opal_async_token_map)) {
+               token = -EBUSY;
+               goto out;
+       }
+
+       __clear_bit(token, opal_async_complete_map);
+
+out:
+       spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+       return token;
+}
+
+int opal_async_get_token_interruptible(void)
+{
+       int token;
+
+       /* Wait until a token is available */
+       if (down_interruptible(&opal_async_sem))
+               return -ERESTARTSYS;
+
+       token = __opal_async_get_token();
+       if (token < 0)
+               up(&opal_async_sem);
+
+       return token;
+}
+
+int __opal_async_release_token(int token)
+{
+       unsigned long flags;
+
+       if (token < 0 || token >= opal_max_async_tokens) {
+               pr_err("%s: Passed token is out of range, token %d\n",
+                               __func__, token);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&opal_async_comp_lock, flags);
+       __set_bit(token, opal_async_complete_map);
+       __clear_bit(token, opal_async_token_map);
+       spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+       return 0;
+}
+
+int opal_async_release_token(int token)
+{
+       int ret;
+
+       ret = __opal_async_release_token(token);
+       if (ret)
+               return ret;
+
+       up(&opal_async_sem);
+
+       return 0;
+}
+
+int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
+{
+       if (token >= opal_max_async_tokens) {
+               pr_err("%s: Invalid token passed\n", __func__);
+               return -EINVAL;
+       }
+
+       if (!msg) {
+               pr_err("%s: Invalid message pointer passed\n", __func__);
+               return -EINVAL;
+       }
+
+       wait_event(opal_async_wait, test_bit(token, opal_async_complete_map));
+       memcpy(msg, &opal_async_responses[token], sizeof(*msg));
+
+       return 0;
+}
+
+static int opal_async_comp_event(struct notifier_block *nb,
+               unsigned long msg_type, void *msg)
+{
+       struct opal_msg *comp_msg = msg;
+       unsigned long flags;
+
+       if (msg_type != OPAL_MSG_ASYNC_COMP)
+               return 0;
+
+       memcpy(&opal_async_responses[comp_msg->params[0]], comp_msg,
+                       sizeof(*comp_msg));
+       spin_lock_irqsave(&opal_async_comp_lock, flags);
+       __set_bit(comp_msg->params[0], opal_async_complete_map);
+       spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+       wake_up(&opal_async_wait);
+
+       return 0;
+}
+
+static struct notifier_block opal_async_comp_nb = {
+               .notifier_call  = opal_async_comp_event,
+               .next           = NULL,
+               .priority       = 0,
+};
+
+static int __init opal_async_comp_init(void)
+{
+       struct device_node *opal_node;
+       const __be32 *async;
+       int err;
+
+       opal_node = of_find_node_by_path("/ibm,opal");
+       if (!opal_node) {
+               pr_err("%s: Opal node not found\n", __func__);
+               err = -ENOENT;
+               goto out;
+       }
+
+       async = of_get_property(opal_node, "opal-msg-async-num", NULL);
+       if (!async) {
+               pr_err("%s: %s has no opal-msg-async-num\n",
+                               __func__, opal_node->full_name);
+               err = -ENOENT;
+               goto out_opal_node;
+       }
+
+       opal_max_async_tokens = be32_to_cpup(async);
+       if (opal_max_async_tokens > N_ASYNC_COMPLETIONS)
+               opal_max_async_tokens = N_ASYNC_COMPLETIONS;
+
+       err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP,
+                       &opal_async_comp_nb);
+       if (err) {
+               pr_err("%s: Can't register OPAL event notifier (%d)\n",
+                               __func__, err);
+               goto out_opal_node;
+       }
+
+       opal_async_responses = kzalloc(
+                       sizeof(*opal_async_responses) * opal_max_async_tokens,
+                       GFP_KERNEL);
+       if (!opal_async_responses) {
+               pr_err("%s: Out of memory, failed to do asynchronous "
+                               "completion init\n", __func__);
+               err = -ENOMEM;
+               goto out_opal_node;
+       }
+
+       /* Initialize to 1 less than the maximum tokens available, as we may
+        * require to pop one during emergency through synchronous call to
+        * __opal_async_get_token()
+        */
+       sema_init(&opal_async_sem, opal_max_async_tokens - 1);
+
+out_opal_node:
+       of_node_put(opal_node);
+out:
+       return err;
+}
+subsys_initcall(opal_async_comp_init);
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
new file mode 100644 (file)
index 0000000..663cc9c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * PowerNV sensor code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <asm/opal.h>
+
+static DEFINE_MUTEX(opal_sensor_mutex);
+
+/*
+ * This will return sensor information to driver based on the requested sensor
+ * handle. A handle is an opaque id for the powernv, read by the driver from the
+ * device tree..
+ */
+int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
+{
+       int ret, token;
+       struct opal_msg msg;
+
+       token = opal_async_get_token_interruptible();
+       if (token < 0) {
+               pr_err("%s: Couldn't get the token, returning\n", __func__);
+               ret = token;
+               goto out;
+       }
+
+       mutex_lock(&opal_sensor_mutex);
+       ret = opal_sensor_read(sensor_hndl, token, sensor_data);
+       if (ret != OPAL_ASYNC_COMPLETION)
+               goto out_token;
+
+       ret = opal_async_wait_response(token, &msg);
+       if (ret) {
+               pr_err("%s: Failed to wait for the async response, %d\n",
+                               __func__, ret);
+               goto out_token;
+       }
+
+       ret = msg.params[1];
+
+out_token:
+       mutex_unlock(&opal_sensor_mutex);
+       opal_async_release_token(token);
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(opal_get_sensor_data);
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
new file mode 100644 (file)
index 0000000..0bd249a
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * PowerNV system parameter code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kobject.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <asm/opal.h>
+
+#define MAX_PARAM_DATA_LEN     64
+
+static DEFINE_MUTEX(opal_sysparam_mutex);
+static struct kobject *sysparam_kobj;
+static void *param_data_buf;
+
+struct param_attr {
+       struct list_head list;
+       u32 param_id;
+       u32 param_size;
+       struct kobj_attribute kobj_attr;
+};
+
+static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
+{
+       struct opal_msg msg;
+       int ret, token;
+
+       token = opal_async_get_token_interruptible();
+       if (token < 0) {
+               if (token != -ERESTARTSYS)
+                       pr_err("%s: Couldn't get the token, returning\n",
+                                       __func__);
+               ret = token;
+               goto out;
+       }
+
+       ret = opal_get_param(token, param_id, (u64)buffer, length);
+       if (ret != OPAL_ASYNC_COMPLETION)
+               goto out_token;
+
+       ret = opal_async_wait_response(token, &msg);
+       if (ret) {
+               pr_err("%s: Failed to wait for the async response, %d\n",
+                               __func__, ret);
+               goto out_token;
+       }
+
+       ret = msg.params[1];
+
+out_token:
+       opal_async_release_token(token);
+out:
+       return ret;
+}
+
+static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
+{
+       struct opal_msg msg;
+       int ret, token;
+
+       token = opal_async_get_token_interruptible();
+       if (token < 0) {
+               if (token != -ERESTARTSYS)
+                       pr_err("%s: Couldn't get the token, returning\n",
+                                       __func__);
+               ret = token;
+               goto out;
+       }
+
+       ret = opal_set_param(token, param_id, (u64)buffer, length);
+
+       if (ret != OPAL_ASYNC_COMPLETION)
+               goto out_token;
+
+       ret = opal_async_wait_response(token, &msg);
+       if (ret) {
+               pr_err("%s: Failed to wait for the async response, %d\n",
+                               __func__, ret);
+               goto out_token;
+       }
+
+       ret = msg.params[1];
+
+out_token:
+       opal_async_release_token(token);
+out:
+       return ret;
+}
+
+static ssize_t sys_param_show(struct kobject *kobj,
+               struct kobj_attribute *kobj_attr, char *buf)
+{
+       struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+                       kobj_attr);
+       int ret;
+
+       mutex_lock(&opal_sysparam_mutex);
+       ret = opal_get_sys_param(attr->param_id, attr->param_size,
+                       param_data_buf);
+       if (ret)
+               goto out;
+
+       memcpy(buf, param_data_buf, attr->param_size);
+
+out:
+       mutex_unlock(&opal_sysparam_mutex);
+       return ret ? ret : attr->param_size;
+}
+
+static ssize_t sys_param_store(struct kobject *kobj,
+               struct kobj_attribute *kobj_attr, const char *buf, size_t count)
+{
+       struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+                       kobj_attr);
+       int ret;
+
+       mutex_lock(&opal_sysparam_mutex);
+       memcpy(param_data_buf, buf, count);
+       ret = opal_set_sys_param(attr->param_id, attr->param_size,
+                       param_data_buf);
+       mutex_unlock(&opal_sysparam_mutex);
+       return ret ? ret : count;
+}
+
+void __init opal_sys_param_init(void)
+{
+       struct device_node *sysparam;
+       struct param_attr *attr;
+       u32 *id, *size;
+       int count, i;
+       u8 *perm;
+
+       if (!opal_kobj) {
+               pr_warn("SYSPARAM: opal kobject is not available\n");
+               goto out;
+       }
+
+       sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
+       if (!sysparam_kobj) {
+               pr_err("SYSPARAM: Failed to create sysparam kobject\n");
+               goto out;
+       }
+
+       /* Allocate big enough buffer for any get/set transactions */
+       param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
+       if (!param_data_buf) {
+               pr_err("SYSPARAM: Failed to allocate memory for param data "
+                               "buf\n");
+               goto out_kobj_put;
+       }
+
+       sysparam = of_find_node_by_path("/ibm,opal/sysparams");
+       if (!sysparam) {
+               pr_err("SYSPARAM: Opal sysparam node not found\n");
+               goto out_param_buf;
+       }
+
+       if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
+               pr_err("SYSPARAM: Opal sysparam node not compatible\n");
+               goto out_node_put;
+       }
+
+       /* Number of parameters exposed through DT */
+       count = of_property_count_strings(sysparam, "param-name");
+       if (count < 0) {
+               pr_err("SYSPARAM: No string found of property param-name in "
+                               "the node %s\n", sysparam->name);
+               goto out_node_put;
+       }
+
+       id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
+       if (!id) {
+               pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+                               "id\n");
+               goto out_node_put;
+       }
+
+       size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
+       if (!size) {
+               pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+                               "size\n");
+               goto out_free_id;
+       }
+
+       perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
+       if (!perm) {
+               pr_err("SYSPARAM: Failed to allocate memory to read supported "
+                               "action on the parameter");
+               goto out_free_size;
+       }
+
+       if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
+               pr_err("SYSPARAM: Missing property param-id in the DT\n");
+               goto out_free_perm;
+       }
+
+       if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
+               pr_err("SYSPARAM: Missing propery param-len in the DT\n");
+               goto out_free_perm;
+       }
+
+
+       if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
+               pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
+               goto out_free_perm;
+       }
+
+       attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
+       if (!attr) {
+               pr_err("SYSPARAM: Failed to allocate memory for parameter "
+                               "attributes\n");
+               goto out_free_perm;
+       }
+
+       /* For each of the parameters, populate the parameter attributes */
+       for (i = 0; i < count; i++) {
+               sysfs_attr_init(&attr[i].kobj_attr.attr);
+               attr[i].param_id = id[i];
+               attr[i].param_size = size[i];
+               if (of_property_read_string_index(sysparam, "param-name", i,
+                               &attr[i].kobj_attr.attr.name))
+                       continue;
+
+               /* If the parameter is read-only or read-write */
+               switch (perm[i] & 3) {
+               case OPAL_SYSPARAM_READ:
+                       attr[i].kobj_attr.attr.mode = S_IRUGO;
+                       break;
+               case OPAL_SYSPARAM_WRITE:
+                       attr[i].kobj_attr.attr.mode = S_IWUGO;
+                       break;
+               case OPAL_SYSPARAM_RW:
+                       attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
+                       break;
+               default:
+                       break;
+               }
+
+               attr[i].kobj_attr.show = sys_param_show;
+               attr[i].kobj_attr.store = sys_param_store;
+
+               if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
+                       pr_err("SYSPARAM: Failed to create sysfs file %s\n",
+                                       attr[i].kobj_attr.attr.name);
+                       goto out_free_attr;
+               }
+       }
+
+       kfree(perm);
+       kfree(size);
+       kfree(id);
+       of_node_put(sysparam);
+       return;
+
+out_free_attr:
+       kfree(attr);
+out_free_perm:
+       kfree(perm);
+out_free_size:
+       kfree(size);
+out_free_id:
+       kfree(id);
+out_node_put:
+       of_node_put(sysparam);
+out_param_buf:
+       kfree(param_data_buf);
+out_kobj_put:
+       kobject_put(sysparam_kobj);
+out:
+       return;
+}
index 47ec3f738062de2a822dcf38453fecca4f442570..75c89df8d71e95b130dc827e036f25330cc1d6ad 100644 (file)
@@ -140,3 +140,6 @@ 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 2e269c27dd23cc32da546b01f3cad960b080c8ba..e92f2f67640f7db39e18d78ccbb08d6ad12eed7e 100644 (file)
@@ -572,6 +572,8 @@ static int __init opal_init(void)
                opal_flash_init();
                /* Setup platform dump extract interface */
                opal_platform_dump_init();
+               /* Setup system parameters interface */
+               opal_sys_param_init();
        }
 
        return 0;
index 80b1d57c306a997e9b3c0a2933efa00ed1ac946e..2cb8b776c84a5660e5ef225cc004fbdcc9109f96 100644 (file)
@@ -111,6 +111,18 @@ config CMM
          will be reused for other LPARs. The interface allows firmware to
          balance memory across many LPARs.
 
+config HV_PERF_CTRS
+       bool "Hypervisor supplied PMU events (24x7 & GPCI)"
+       default y
+       depends on PERF_EVENTS && PPC_PSERIES
+       help
+         Enable access to hypervisor supplied counters in perf. Currently,
+         this enables code that uses the hcall GetPerfCounterInfo and 24x7
+         interfaces to retrieve counters. GPCI exists on Power 6 and later
+         systems. 24x7 is available on Power 8 systems.
+
+          If unsure, select Y.
+
 config DTL
        bool "Dispatch Trace Log"
        depends on PPC_SPLPAR && DEBUG_FS
index 5ce43d8dfa98e635f039eaad29b5ec4627557b78..ad4cdcbc618bc527265fcad6f442af0deb985223 100644 (file)
@@ -557,6 +557,14 @@ config SENSORS_IBMPEX
          This driver can also be built as a module.  If so, the module
          will be called ibmpex.
 
+config SENSORS_IBMPOWERNV
+       tristate "IBM PowerNv Platform temperature/power/fan sensor"
+       depends on PPC_POWERNV
+       default y
+       help
+         If you say yes here you get support for the temperature/fan/power
+         sensors on your platform.
+
 config SENSORS_IIO_HWMON
        tristate "Hwmon driver that uses channels specified via iio maps"
        depends on IIO
index ec7cde06eb52bb628e1eb67d661d3d652ee91d97..807e1721ed7956bac9d48ffdd462d818762bfb57 100644 (file)
@@ -70,6 +70,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
+obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
 obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
 obj-$(CONFIG_SENSORS_INA209)   += ina209.o
 obj-$(CONFIG_SENSORS_INA2XX)   += ina2xx.o
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
new file mode 100644 (file)
index 0000000..b7b1297
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * hwmon driver for temperature/power/fan on IBM PowerNV platform
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <asm/opal.h>
+#include <linux/err.h>
+
+MODULE_DESCRIPTION("IBM PowerNV Platform power/temp/fan sensor hwmon module");
+MODULE_LICENSE("GPL");
+
+#define MAX_ATTR_LENGTH                32
+
+/* Device tree sensor name prefixes. The device tree has the names in the
+ * format "cooling-fan#2-faulted" where the "cooling-fan" is the sensor type,
+ * 2 is the sensor count, and "faulted" is the sensor data attribute type.
+ */
+#define DT_FAULT_ATTR_SUFFIX           "faulted"
+#define DT_DATA_ATTR_SUFFIX            "data"
+#define DT_THRESHOLD_ATTR_SUFFIX       "thrs"
+
+enum sensors {
+       FAN,
+       TEMPERATURE,
+       POWERSUPPLY,
+       POWER,
+       MAX_SENSOR_TYPE,
+};
+
+enum attributes {
+       INPUT,
+       MINIMUM,
+       MAXIMUM,
+       FAULT,
+       MAX_ATTR_TYPES
+};
+
+static struct sensor_name {
+       char *name;
+       char *compaible;
+} sensor_names[] = {
+               {"fan-sensor", "ibm,opal-sensor-cooling-fan"},
+               {"amb-temp-sensor", "ibm,opal-sensor-amb-temp"},
+               {"power-sensor", "ibm,opal-sensor-power-supply"},
+               {"power", "ibm,opal-sensor-power"}
+};
+
+static const char * const attribute_type_table[] = {
+       "input",
+       "min",
+       "max",
+       "fault",
+       NULL
+};
+
+struct pdev_entry {
+       struct list_head list;
+       struct platform_device *pdev;
+       enum sensors type;
+};
+
+static LIST_HEAD(pdev_list);
+
+/* The sensors are categorised on type.
+ *
+ * The sensors of same type are categorised under a common platform device.
+ * So, The pdev is shared by all sensors of same type.
+ * Ex : temp1_input, temp1_max, temp2_input,temp2_max all share same platform
+ * device.
+ *
+ * "sensor_data" is the Platform device specific data.
+ * There is one hwmon_device instance for all the sensors of same type.
+ * This also holds the list of all sensors with same type but different
+ * attribute and index.
+ */
+struct sensor_specific_data {
+       u32 sensor_id; /* The hex value as in the device tree */
+       u32 sensor_index; /* The sensor instance index */
+       struct sensor_device_attribute sd_attr;
+       enum attributes attr_type;
+       char attr_name[64];
+};
+
+struct sensor_data {
+       struct device *hwmon_dev;
+       struct list_head sensor_list;
+       struct device_attribute name_attr;
+};
+
+struct  sensor_entry {
+       struct list_head list;
+       struct sensor_specific_data *sensor_data;
+};
+
+static struct platform_device *powernv_sensor_get_pdev(enum sensors type)
+{
+       struct pdev_entry *p;
+       list_for_each_entry(p, &pdev_list, list)
+               if (p->type == type)
+                       return p->pdev;
+
+       return NULL;
+}
+
+static struct sensor_specific_data *powernv_sensor_get_sensor_data(
+                                       struct sensor_data *pdata,
+                                       int index, enum attributes attr_type)
+{
+       struct sensor_entry *p;
+       list_for_each_entry(p, &pdata->sensor_list, list)
+               if ((p->sensor_data->sensor_index == index) &&
+                   (attr_type == p->sensor_data->attr_type))
+                       return p->sensor_data;
+
+       return NULL;
+}
+
+static ssize_t show_name(struct device *dev,
+                               struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return sprintf(buf, "%s\n", pdev->name);
+}
+
+/* Note: Data from the sensors for each sensor type needs to be converted to
+ * the dimension appropriate.
+ */
+static ssize_t show_sensor(struct device *dev,
+                               struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(devattr);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sensor_data *pdata = platform_get_drvdata(pdev);
+       struct sensor_specific_data *tdata = NULL;
+       enum sensors sensor_type = pdev->id;
+       u32 x = -1;
+       int ret;
+
+       if (sd_attr && sd_attr->dev_attr.attr.name) {
+               char *pos = strchr(sd_attr->dev_attr.attr.name, '_');
+               int i;
+
+               for (i = 0; i < MAX_ATTR_TYPES; i++) {
+                       if (strcmp(pos+1, attribute_type_table[i]) == 0) {
+                               tdata = powernv_sensor_get_sensor_data(pdata,
+                                               sd_attr->index, i);
+                               break;
+                       }
+               }
+       }
+
+       if (tdata) {
+               ret = opal_get_sensor_data(tdata->sensor_id, &x);
+               if (ret)
+                       x = -1;
+       }
+
+       if (sensor_type == TEMPERATURE && x > 0) {
+               /* Temperature comes in Degrees and convert it to
+                * milli-degrees.
+                */
+               x = x*1000;
+       } else if (sensor_type == POWER && x > 0) {
+               /* Power value comes in watts, convert to micro-watts */
+               x = x * 1000000;
+       }
+
+       return sprintf(buf, "%d\n", x);
+}
+
+static u32 get_sensor_index_from_name(const char *name)
+{
+       char *hash_position = strchr(name, '#');
+       u32 index = 0, copy_length;
+       char newbuf[8];
+
+       if (hash_position) {
+               copy_length = strchr(hash_position, '-') - hash_position - 1;
+               if (copy_length < sizeof(newbuf)) {
+                       strncpy(newbuf, hash_position + 1, copy_length);
+                       sscanf(newbuf, "%d", &index);
+               }
+       }
+
+       return index;
+}
+
+static inline void get_sensor_suffix_from_name(const char *name, char *suffix)
+{
+       char *dash_position = strrchr(name, '-');
+       if (dash_position)
+               strncpy(suffix, dash_position+1, MAX_ATTR_LENGTH);
+       else
+               strcpy(suffix,"");
+}
+
+static int get_sensor_attr_properties(const char *sensor_name,
+               enum sensors sensor_type, enum attributes *attr_type,
+               u32 *sensor_index)
+{
+       char suffix[MAX_ATTR_LENGTH];
+
+       *attr_type = MAX_ATTR_TYPES;
+       *sensor_index = get_sensor_index_from_name(sensor_name);
+       if (*sensor_index == 0)
+               return -EINVAL;
+
+       get_sensor_suffix_from_name(sensor_name, suffix);
+       if (strcmp(suffix, "") == 0)
+               return -EINVAL;
+
+       if (strcmp(suffix, DT_FAULT_ATTR_SUFFIX) == 0)
+               *attr_type = FAULT;
+       else if (strcmp(suffix, DT_DATA_ATTR_SUFFIX) == 0)
+               *attr_type = INPUT;
+       else if ((sensor_type == TEMPERATURE) &&
+                       (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+               *attr_type = MAXIMUM;
+       else if ((sensor_type == FAN) &&
+                       (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+               *attr_type = MINIMUM;
+       else
+               return -ENOENT;
+
+       if (((sensor_type == FAN) && ((*attr_type == INPUT) ||
+                                   (*attr_type == MINIMUM)))
+           || ((sensor_type == TEMPERATURE) && ((*attr_type == INPUT) ||
+                                                (*attr_type == MAXIMUM)))
+           || ((sensor_type == POWER) && ((*attr_type == INPUT))))
+               return 0;
+
+       return -ENOENT;
+}
+
+static int create_sensor_attr(struct sensor_specific_data *tdata,
+               struct device *dev, enum sensors sensor_type,
+               enum attributes attr_type)
+{
+       int err = 0;
+       char temp_file_prefix[50];
+       static const char *const file_name_format = "%s%d_%s";
+
+       tdata->attr_type = attr_type;
+
+       if (sensor_type == FAN)
+               strcpy(temp_file_prefix, "fan");
+       else if (sensor_type == TEMPERATURE)
+               strcpy(temp_file_prefix, "temp");
+       else if (sensor_type == POWERSUPPLY)
+               strcpy(temp_file_prefix, "powersupply");
+       else if (sensor_type == POWER)
+               strcpy(temp_file_prefix, "power");
+
+       snprintf(tdata->attr_name, sizeof(tdata->attr_name), file_name_format,
+                temp_file_prefix, tdata->sensor_index,
+                attribute_type_table[tdata->attr_type]);
+
+       sysfs_attr_init(&tdata->sd_attr.dev_attr.attr);
+       tdata->sd_attr.dev_attr.attr.name = tdata->attr_name;
+       tdata->sd_attr.dev_attr.attr.mode = S_IRUGO;
+       tdata->sd_attr.dev_attr.show = show_sensor;
+
+       tdata->sd_attr.index = tdata->sensor_index;
+       err = device_create_file(dev, &tdata->sd_attr.dev_attr);
+
+       return err;
+}
+
+static int create_name_attr(struct sensor_data *pdata,
+                               struct device *dev)
+{
+       sysfs_attr_init(&pdata->name_attr.attr);
+       pdata->name_attr.attr.name = "name";
+       pdata->name_attr.attr.mode = S_IRUGO;
+       pdata->name_attr.show = show_name;
+       return device_create_file(dev, &pdata->name_attr);
+}
+
+static int create_platform_device(enum sensors sensor_type,
+                                       struct platform_device **pdev)
+{
+       struct pdev_entry *pdev_entry = NULL;
+       int err;
+
+       *pdev = platform_device_alloc(sensor_names[sensor_type].name,
+                       sensor_type);
+       if (!*pdev) {
+               pr_err("Device allocation failed\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+       if (!pdev_entry) {
+               pr_err("Device allocation failed\n");
+               err = -ENOMEM;
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(*pdev);
+       if (err) {
+               pr_err("Device addition failed (%d)\n", err);
+               goto exit_device_free;
+       }
+
+       pdev_entry->pdev = *pdev;
+       pdev_entry->type = (*pdev)->id;
+
+       list_add_tail(&pdev_entry->list, &pdev_list);
+
+       return 0;
+exit_device_free:
+       kfree(pdev_entry);
+exit_device_put:
+       platform_device_put(*pdev);
+exit:
+       return err;
+}
+
+static int create_sensor_data(struct platform_device *pdev)
+{
+       struct sensor_data *pdata = NULL;
+       int err = 0;
+
+       pdata = kzalloc(sizeof(struct sensor_data), GFP_KERNEL);
+       if (!pdata) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       err = create_name_attr(pdata, &pdev->dev);
+       if (err)
+               goto exit_free;
+
+       pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(pdata->hwmon_dev)) {
+               err = PTR_ERR(pdata->hwmon_dev);
+               dev_err(&pdev->dev, "Class registration failed (%d)\n",
+                       err);
+               goto exit_name;
+       }
+
+       INIT_LIST_HEAD(&pdata->sensor_list);
+       platform_set_drvdata(pdev, pdata);
+
+       return 0;
+
+exit_name:
+       device_remove_file(&pdev->dev, &pdata->name_attr);
+exit_free:
+       kfree(pdata);
+exit:
+       return err;
+}
+
+static void delete_sensor_attr(struct sensor_data *pdata)
+{
+       struct sensor_entry *s, *l;
+
+       list_for_each_entry_safe(s, l, &pdata->sensor_list, list) {
+               struct sensor_specific_data *tdata = s->sensor_data;
+                       kfree(tdata);
+                       list_del(&s->list);
+                       kfree(s);
+               }
+}
+
+static int powernv_sensor_init(u32 sensor_id, const struct device_node *np,
+               enum sensors sensor_type, enum attributes attr_type,
+               u32 sensor_index)
+{
+       struct platform_device *pdev = powernv_sensor_get_pdev(sensor_type);
+       struct sensor_specific_data *tdata;
+       struct sensor_entry *sensor_entry;
+       struct sensor_data *pdata;
+       int err = 0;
+
+       if (!pdev) {
+               err = create_platform_device(sensor_type, &pdev);
+               if (err)
+                       goto exit;
+
+               err = create_sensor_data(pdev);
+               if (err)
+                       goto exit;
+       }
+
+       pdata = platform_get_drvdata(pdev);
+       if (!pdata) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       tdata = kzalloc(sizeof(struct sensor_specific_data), GFP_KERNEL);
+       if (!tdata) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       tdata->sensor_id = sensor_id;
+       tdata->sensor_index = sensor_index;
+
+       err = create_sensor_attr(tdata, &pdev->dev, sensor_type, attr_type);
+       if (err)
+               goto exit_free;
+
+       sensor_entry = kzalloc(sizeof(struct sensor_entry), GFP_KERNEL);
+       if (!sensor_entry) {
+               err = -ENOMEM;
+               goto exit_attr;
+       }
+
+       sensor_entry->sensor_data = tdata;
+
+       list_add_tail(&sensor_entry->list, &pdata->sensor_list);
+
+       return 0;
+exit_attr:
+       device_remove_file(&pdev->dev, &tdata->sd_attr.dev_attr);
+exit_free:
+       kfree(tdata);
+exit:
+       return err;
+}
+
+static void delete_unregister_sensors(void)
+{
+       struct pdev_entry *p, *n;
+
+       list_for_each_entry_safe(p, n, &pdev_list, list) {
+               struct sensor_data *pdata = platform_get_drvdata(p->pdev);
+                       if (pdata) {
+                               delete_sensor_attr(pdata);
+
+                               hwmon_device_unregister(pdata->hwmon_dev);
+                               kfree(pdata);
+                       }
+               platform_device_unregister(p->pdev);
+               list_del(&p->list);
+               kfree(p);
+       }
+}
+
+static int __init powernv_hwmon_init(void)
+{
+       struct device_node *opal, *np = NULL;
+       enum attributes attr_type;
+       enum sensors type;
+       const u32 *sensor_id;
+       u32 sensor_index;
+       int err;
+
+       opal = of_find_node_by_path("/ibm,opal/sensors");
+       if (!opal) {
+               pr_err("%s: Opal 'sensors' node not found\n", __func__);
+               return -ENXIO;
+       }
+
+       for_each_child_of_node(opal, np) {
+               if (np->name == NULL)
+                       continue;
+
+               for (type = 0; type < MAX_SENSOR_TYPE; type++)
+                       if (of_device_is_compatible(np,
+                                       sensor_names[type].compaible))
+                               break;
+
+               if (type == MAX_SENSOR_TYPE)
+                       continue;
+
+               if (get_sensor_attr_properties(np->name, type, &attr_type,
+                               &sensor_index))
+                       continue;
+
+               sensor_id = of_get_property(np, "sensor-id", NULL);
+               if (!sensor_id) {
+                       pr_info("%s: %s doesn't have sensor-id\n", __func__,
+                                       np->name);
+                       continue;
+               }
+
+               err = powernv_sensor_init(*sensor_id, np, type, attr_type,
+                               sensor_index);
+               if (err) {
+                       of_node_put(opal);
+                       goto exit;
+               }
+       }
+       of_node_put(opal);
+
+       return 0;
+exit:
+       delete_unregister_sensors();
+       return err;
+
+}
+
+static void powernv_hwmon_exit(void)
+{
+       delete_unregister_sensors();
+}
+
+module_init(powernv_hwmon_init);
+module_exit(powernv_hwmon_exit);
index 6b579387c67a143d14550ff8f272bb370348c649..aa0406895b53efe76501dc650f41f3ceb5d3b877 100644 (file)
@@ -70,8 +70,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
        if (grp->bin_attrs) {
                for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
                        if (update)
-                               sysfs_remove_bin_file(kobj, *bin_attr);
-                       error = sysfs_create_bin_file(kobj, *bin_attr);
+                               kernfs_remove_by_name(parent,
+                                               (*bin_attr)->attr.name);
+                       error = sysfs_add_file_mode_ns(parent,
+                                       &(*bin_attr)->attr, true,
+                                       (*bin_attr)->attr.mode, NULL);
                        if (error)
                                break;
                }