diff options
42 files changed, 3122 insertions, 289 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events index 3c1cc24361bd..7b40a3cbc26a 100644 --- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events @@ -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 index 000000000000..e78ee798d7bd --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 @@ -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 index 000000000000..3fa58c23f13b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci @@ -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. diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..27030d573d88 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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/ diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index e015896b7e5c..f26b267eb71f 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -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 diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig index f627fda08953..438e813dc9cb 100644 --- a/arch/powerpc/configs/ppc64e_defconfig +++ b/arch/powerpc/configs/ppc64e_defconfig @@ -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 diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index e9a8b4e0a0f6..9ea8342bd219 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -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 diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig index 62771e0adb7c..3c84f9d87980 100644 --- a/arch/powerpc/configs/pseries_le_defconfig +++ b/arch/powerpc/configs/pseries_le_defconfig @@ -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 diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index a613d2c82fd9..b142b8e0ed9e 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -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; diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 617cc767c076..bc2347774f0a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -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 { diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 66830618cc19..aeaa56cd9b54 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -147,6 +147,14 @@ BEGIN_FTR_SECTION_NESTED(943) \ 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 */ #define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \ diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index d8b600b3f058..5dbbb29f5c3e 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -274,6 +274,11 @@ /* 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__ /** diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 2636acfcd340..ffafab037ba8 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -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); diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 3fd2f1b6f906..9ed737146dbb 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -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 diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index f7251c2dc049..1a36b8ede417 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -668,12 +668,14 @@ #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 */ @@ -707,6 +709,7 @@ #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 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 6c8dd5da4de5..c1faade6506d 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -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, diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 38d507306a11..4c34c3c827ad 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -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) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 4cf674d7d5ae..f386296ff378 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -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; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 33cd7a0b8e73..df86f0ce2d36 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -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); diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 62bf5e8e78da..f6ce1f111f5b 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -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(); } /* diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile index 60d71eea919c..f9c083a5652a 100644 --- a/arch/powerpc/perf/Makefile +++ b/arch/powerpc/perf/Makefile @@ -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) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 67cf22083f4c..4520c9356b54 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -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 index 000000000000..21b19dd86d9c --- /dev/null +++ b/arch/powerpc/perf/hv-24x7-catalog.h @@ -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 index 000000000000..297c91051413 --- /dev/null +++ b/arch/powerpc/perf/hv-24x7.c @@ -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 index 000000000000..720ebce4b435 --- /dev/null +++ b/arch/powerpc/perf/hv-24x7.h @@ -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 index 000000000000..47e02b366f58 --- /dev/null +++ b/arch/powerpc/perf/hv-common.c @@ -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 index 000000000000..5d79cecbd73d --- /dev/null +++ b/arch/powerpc/perf/hv-common.h @@ -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 index 000000000000..278ba7b9c2b5 --- /dev/null +++ b/arch/powerpc/perf/hv-gpci.c @@ -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 index 000000000000..b25f460c9cce --- /dev/null +++ b/arch/powerpc/perf/hv-gpci.h @@ -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 diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h index 687790a2c0b8..64f13d9260a6 100644 --- a/arch/powerpc/perf/power7-events-list.h +++ b/arch/powerpc/perf/power7-events-list.h @@ -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) diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c index 96cee20dcd34..fe2763b6e039 100644 --- a/arch/powerpc/perf/power8-pmu.c +++ b/arch/powerpc/perf/power8-pmu.c @@ -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> @@ -62,9 +64,11 @@ * * 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 * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | @@ -114,9 +118,18 @@ * 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) */ @@ -141,6 +154,12 @@ #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) | \ @@ -149,7 +168,7 @@ (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 */ @@ -173,10 +192,11 @@ * * 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 @@ -195,6 +215,9 @@ #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) @@ -241,6 +264,7 @@ #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); diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 5125caeb40f4..f324ea099503 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -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 index 000000000000..cd0c1354d404 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-async.c @@ -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 index 000000000000..663cc9c65613 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-sensor.c @@ -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 index 000000000000..0bd249a26f30 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-sysparam.c @@ -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; +} diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 47ec3f738062..75c89df8d71e 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -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); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 2e269c27dd23..e92f2f67640f 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -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; diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 80b1d57c306a..2cb8b776c84a 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -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 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5ce43d8dfa98..ad4cdcbc618b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index ec7cde06eb52..807e1721ed79 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -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 index 000000000000..b7b1297a9b02 --- /dev/null +++ b/drivers/hwmon/ibmpowernv.c @@ -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); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 6b579387c67a..aa0406895b53 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -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; } |