Perf: Upgrade 8660 L2CC PMU perf support

Upgrade the perfevents API of 8660 L2CC PMU to work with
the newer infrastructure.

Change-Id: Ib3dc966455f6f4bb680a222c458551b90cfb6b70
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 53e9999..a40f81e 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -25,6 +25,7 @@
 	ARM_PERF_PMU_ID_CA7,
 	ARM_PERF_PMU_ID_SCORPION,
 	ARM_PERF_PMU_ID_SCORPIONMP,
+	ARM_PERF_PMU_ID_SCORPIONMP_L2,
 	ARM_PERF_PMU_ID_KRAIT,
 	ARM_PERF_PMU_ID_KRAIT_L2,
 	ARM_NUM_PMU_IDS,
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
deleted file mode 100644
index 26753d8..0000000
--- a/arch/arm/kernel/perf_event_msm_l2.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
- */
-#ifdef CONFIG_ARCH_MSM8X60
-
-#include <linux/irq.h>
-
-#define MAX_BB_L2_PERIOD	((1ULL << 32) - 1)
-#define MAX_BB_L2_CTRS 5
-#define BB_L2CYCLE_CTR_BIT 31
-#define BB_L2CYCLE_CTR_EVENT_IDX 4
-#define BB_L2CYCLE_CTR_RAW_CODE 0xfe
-#define SCORPIONL2_PMNC_E       (1 << 0)	/* Enable all counters */
-#define SCORPION_L2_EVT_PREFIX 3
-#define SCORPION_MAX_L2_REG 4
-
-/*
- * Lock to protect r/m/w sequences to the L2 PMU.
- */
-DEFINE_RAW_SPINLOCK(bb_l2_pmu_lock);
-
-static struct platform_device *bb_l2_pmu_device;
-
-struct hw_bb_l2_pmu {
-	struct perf_event *events[MAX_BB_L2_CTRS];
-	unsigned long active_mask[BITS_TO_LONGS(MAX_BB_L2_CTRS)];
-	raw_spinlock_t lock;
-};
-
-struct hw_bb_l2_pmu hw_bb_l2_pmu;
-
-struct bb_l2_scorp_evt {
-	u32 evt_type;
-	u32 val;
-	u8 grp;
-	u32 evt_type_act;
-};
-
-enum scorpion_perf_types {
-	SCORPIONL2_TOTAL_BANK_REQ = 0x90,
-	SCORPIONL2_DSIDE_READ = 0x91,
-	SCORPIONL2_DSIDE_WRITE = 0x92,
-	SCORPIONL2_ISIDE_READ = 0x93,
-	SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
-	SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
-	SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
-	SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
-	SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
-	SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
-	SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
-	SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
-	SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
-	SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
-	SCORPIONL2_BARRIERS = 0x9e,
-	SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
-	SCORPIONL2_MVA_POC = 0xa0,
-	SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
-	SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
-	SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
-	SCORPIONL2_ISIDE_READ_HITS = 0xa4,
-	SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
-	SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
-	SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
-	SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
-	SCORPIONL2_L2LINE_LOCKED = 0xa9,
-	SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
-	SCORPIONL2_CACHE_MVA_POC = 0xab,
-	SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
-	SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
-	SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
-	SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
-	SCORPIONL2_PMBUS_MPAAF = 0xb0,
-	SCORPIONL2_PMBUS_MPWDAF = 0xb1,
-	SCORPIONL2_PMBUS_MPBRT = 0xb2,
-	SCORPIONL2_CPU0_GRANT = 0xb3,
-	SCORPIONL2_CPU1_GRANT = 0xb4,
-	SCORPIONL2_CPU0_NOGRANT = 0xb5,
-	SCORPIONL2_CPU1_NOGRANT = 0xb6,
-	SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
-	SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
-	SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
-	SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
-	SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
-	SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
-	SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
-	SCORPIONL2_L2EM_STREX_PASS = 0xbe,
-	SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
-	SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
-	SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
-	SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
-	SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
-	SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
-	SCORPIONL2_CPU0_CLAMPED = 0xc5,
-	SCORPIONL2_CPU1_CLAMPED = 0xc6,
-	SCORPIONL2_CPU0_WAIT = 0xc7,
-	SCORPIONL2_CPU1_WAIT = 0xc8,
-	SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
-	SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
-	SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
-	SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
-	SCORPIONL2_AXI_READ = 0xcd,
-	SCORPIONL2_AXI_WRITE = 0xce,
-
-	SCORPIONL2_1BEAT_WRITE = 0xcf,
-	SCORPIONL2_2BEAT_WRITE = 0xd0,
-	SCORPIONL2_4BEAT_WRITE = 0xd1,
-	SCORPIONL2_8BEAT_WRITE = 0xd2,
-	SCORPIONL2_12BEAT_WRITE = 0xd3,
-	SCORPIONL2_16BEAT_WRITE = 0xd4,
-	SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
-	SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
-	SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
-	SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
-	SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
-	SCORPIONL2_CSYS_READ_2BEAT = 0xda,
-	SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
-	SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
-	SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
-	SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
-	SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
-	SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
-	SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
-	SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
-	SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
-	SCORPIONL2_LDREX_REQ = 0xe4,
-	SCORPIONL2_STREX_PASS = 0xe5,
-	SCORPIONL2_STREX_FAIL = 0xe6,
-	SCORPIONL2_CPREAD = 0xe7,
-	SCORPIONL2_CPWRITE = 0xe8,
-	SCORPIONL2_BARRIER_REQ = 0xe9,
-	SCORPIONL2_AXI_READ_SLVPORT = 0xea,
-	SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
-	SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
-	SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
-	SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
-	SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
-	SCORPIONL2_SNOOPED_IC = 0xf0,
-	SCORPIONL2_SNOOPED_BP = 0xf1,
-	SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
-	SCORPIONL2_SNOOPED_TLB = 0xf3,
-	BB_L2_MAX_EVT,
-};
-
-static const struct bb_l2_scorp_evt sc_evt[] = {
-	{SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
-	{SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
-	{SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
-	{SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
-	{SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
-	{SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
-	{SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
-	{SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
-	{SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
-	{SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
-	{SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
-	{SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
-	{SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
-	{SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
-	{SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
-	{SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
-	{SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
-	{SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
-	{SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
-	{SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
-	{SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
-	{SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
-	{SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
-	{SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
-	{SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
-	{SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
-	{SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
-	{SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
-	{SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
-	{SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
-	{SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
-	{SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
-	{SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
-	{SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
-	{SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
-
-	{SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
-	{SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
-	{SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
-	{SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
-	{SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
-	{SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
-	{SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
-	{SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
-	{SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
-	{SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
-	{SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
-	{SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
-	{SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
-	{SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
-	{SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
-	{SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
-	{SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
-	{SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
-	{SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
-	{SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
-	{SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
-	{SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
-	{SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
-
-	{SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
-	{SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
-	{SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
-	{SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
-	{SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
-	{SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
-	{SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
-	{SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
-	{SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
-	{SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
-	{SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
-	{SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
-	{SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
-	{SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
-	{SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
-	{SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
-	{SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
-	{SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
-	{SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
-	{SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
-	{SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
-	{SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
-	{SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
-	{SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
-	{SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
-	{SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
-	{SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
-	{SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
-	{SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
-
-	{SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
-	{SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
-	{SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
-	{SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
-
-	{SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
-	{SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
-	{SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
-	{SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
-	{SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
-	{SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
-};
-
-static u32 bb_l2_read_l2pm0(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm0(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm1(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm1(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm2(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm2(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm3(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm3(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm4(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm4(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
-}
-
-struct bb_scorpion_access_funcs {
-	u32(*read) (void);
-	void (*write) (u32);
-	void (*pre) (void);
-	void (*post) (void);
-};
-
-struct bb_scorpion_access_funcs bb_l2_func[] = {
-	{bb_l2_read_l2pm0, bb_l2_write_l2pm0, NULL, NULL},
-	{bb_l2_read_l2pm1, bb_l2_write_l2pm1, NULL, NULL},
-	{bb_l2_read_l2pm2, bb_l2_write_l2pm2, NULL, NULL},
-	{bb_l2_read_l2pm3, bb_l2_write_l2pm3, NULL, NULL},
-	{bb_l2_read_l2pm4, bb_l2_write_l2pm4, NULL, NULL},
-};
-
-#define COLMN0MASK 0x000000ff
-#define COLMN1MASK 0x0000ff00
-#define COLMN2MASK 0x00ff0000
-
-static u32 bb_l2_get_columnmask(u32 setval)
-{
-	if (setval & COLMN0MASK)
-		return 0xffffff00;
-	else if (setval & COLMN1MASK)
-		return 0xffff00ff;
-	else if (setval & COLMN2MASK)
-		return 0xff00ffff;
-	else
-		return 0x80ffffff;
-}
-
-static void bb_l2_evt_setup(u32 gr, u32 setval)
-{
-	u32 val;
-	if (bb_l2_func[gr].pre)
-		bb_l2_func[gr].pre();
-	val = bb_l2_get_columnmask(setval) & bb_l2_func[gr].read();
-	val = val | setval;
-	bb_l2_func[gr].write(val);
-	if (bb_l2_func[gr].post)
-		bb_l2_func[gr].post();
-}
-
-#define BB_L2_EVT_START_IDX 0x90
-#define BB_L2_INV_EVTYPE 0
-
-static unsigned int get_bb_l2_evtinfo(unsigned int evt_type,
-				      struct bb_l2_scorp_evt *evtinfo)
-{
-	u32 idx;
-	u8 prefix;
-	u8 reg;
-	u8 code;
-	u8 group;
-
-	prefix = (evt_type & 0xF0000) >> 16;
-	if (prefix == SCORPION_L2_EVT_PREFIX) {
-		reg   = (evt_type & 0x0F000) >> 12;
-		code  = (evt_type & 0x00FF0) >> 4;
-		group =  evt_type & 0x0000F;
-
-		if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
-			return BB_L2_INV_EVTYPE;
-
-		evtinfo->val = 0x80000000 | (code << (group * 8));
-		evtinfo->grp = reg;
-		evtinfo->evt_type_act = group | (reg << 2);
-		return evtinfo->evt_type_act;
-	}
-
-	if (evt_type < BB_L2_EVT_START_IDX || evt_type >= BB_L2_MAX_EVT)
-		return BB_L2_INV_EVTYPE;
-	idx = evt_type - BB_L2_EVT_START_IDX;
-	if (sc_evt[idx].evt_type == evt_type) {
-		evtinfo->val = sc_evt[idx].val;
-		evtinfo->grp = sc_evt[idx].grp;
-		evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
-		return sc_evt[idx].evt_type_act;
-	}
-	return BB_L2_INV_EVTYPE;
-}
-
-static inline void bb_l2_pmnc_write(unsigned long val)
-{
-	val &= 0xff;
-	asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
-}
-
-static inline unsigned long bb_l2_pmnc_read(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_set_evcntcr(void)
-{
-	u32 val = 0x0;
-	asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
-}
-
-static inline void bb_l2_set_evtyper(int ctr, int val)
-{
-	/* select ctr */
-	asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
-
-	/* write into EVTYPER */
-	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
-}
-
-static void bb_l2_set_evfilter_task_mode(void)
-{
-	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
-
-	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_set_evfilter_sys_mode(void)
-{
-	u32 filter_val = 0x000f003f;
-
-	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_enable_intenset(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_disable_intenclr(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_enable_counter(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_disable_counter(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
-	}
-}
-
-static u64 bb_l2_read_counter(u32 idx)
-{
-	u32 val;
-	unsigned long flags;
-
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
-	} else {
-		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
-		/* read val from counter */
-		asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
-		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	}
-
-	return val;
-}
-
-static void bb_l2_write_counter(u32 idx, u32 val)
-{
-	unsigned long flags;
-
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
-	} else {
-		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-		/* select counter */
-		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
-		/* write val into counter */
-		asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
-		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	}
-}
-
-static int
-bb_pmu_event_set_period(struct perf_event *event,
-			struct hw_perf_event *hwc, int idx)
-{
-	s64 left = local64_read(&hwc->period_left);
-	s64 period = hwc->sample_period;
-	int ret = 0;
-
-	if (unlikely(left <= -period)) {
-		left = period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (unlikely(left <= 0)) {
-		left += period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (left > (s64) MAX_BB_L2_PERIOD)
-		left = MAX_BB_L2_PERIOD;
-
-	local64_set(&hwc->prev_count, (u64)-left);
-
-	bb_l2_write_counter(idx, (u64) (-left) & 0xffffffff);
-
-	perf_event_update_userpage(event);
-
-	return ret;
-}
-
-static u64
-bb_pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc,
-		    int idx, int overflow)
-{
-	u64 prev_raw_count, new_raw_count;
-	u64 delta;
-
-again:
-	prev_raw_count = local64_read(&hwc->prev_count);
-	new_raw_count = bb_l2_read_counter(idx);
-
-	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
-			    new_raw_count) != prev_raw_count)
-		goto again;
-
-	new_raw_count &= MAX_BB_L2_PERIOD;
-	prev_raw_count &= MAX_BB_L2_PERIOD;
-
-	if (overflow) {
-		delta = MAX_BB_L2_PERIOD - prev_raw_count + new_raw_count;
-		pr_err("%s: delta: %lld\n", __func__, delta);
-	} else
-		delta = new_raw_count - prev_raw_count;
-
-	local64_add(delta, &event->count);
-	local64_sub(delta, &hwc->period_left);
-
-	pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
-		 __func__, new_raw_count, prev_raw_count,
-		 hwc->config_base, local64_read(&event->count));
-
-	return new_raw_count;
-}
-
-static void bb_l2_read(struct perf_event *event)
-{
-	struct hw_perf_event *hwc = &event->hw;
-
-	bb_pmu_event_update(event, hwc, hwc->idx, 0);
-}
-
-static void bb_l2_stop_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-
-	if (!(hwc->state & PERF_HES_STOPPED)) {
-		bb_l2_disable_intenclr(idx);
-		bb_l2_disable_counter(idx);
-
-		bb_pmu_event_update(event, hwc, idx, 0);
-		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
-	}
-
-	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
-		 idx);
-}
-
-static void bb_l2_start_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	struct bb_l2_scorp_evt evtinfo;
-	int evtype = hwc->config_base;
-	int ev_typer;
-	unsigned long iflags;
-	int cpu_id = smp_processor_id();
-
-	if (flags & PERF_EF_RELOAD)
-		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
-
-	hwc->state = 0;
-
-	bb_pmu_event_set_period(event, hwc, idx);
-
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE)
-		goto out;
-
-	memset(&evtinfo, 0, sizeof(evtinfo));
-
-	ev_typer = get_bb_l2_evtinfo(evtype, &evtinfo);
-
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, iflags);
-
-	bb_l2_set_evtyper(idx, ev_typer);
-
-	bb_l2_set_evcntcr();
-
-	if (event->cpu < 0)
-		bb_l2_set_evfilter_task_mode();
-	else
-		bb_l2_set_evfilter_sys_mode();
-
-	bb_l2_evt_setup(evtinfo.grp, evtinfo.val);
-
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, iflags);
-
-out:
-
-	bb_l2_enable_intenset(idx);
-
-	bb_l2_enable_counter(idx);
-
-	pr_debug("%s: idx: %d, event: %d, val: %x, cpu: %d\n",
-		 __func__, idx, evtype, evtinfo.val, cpu_id);
-}
-
-static void bb_l2_del_event(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	unsigned long iflags;
-
-	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
-	clear_bit(idx, (long unsigned int *)(&hw_bb_l2_pmu.active_mask));
-
-	bb_l2_stop_counter(event, PERF_EF_UPDATE);
-	hw_bb_l2_pmu.events[idx] = NULL;
-	hwc->idx = -1;
-
-	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
-	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
-
-	perf_event_update_userpage(event);
-}
-
-static int bb_l2_add_event(struct perf_event *event, int flags)
-{
-	int ctr = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	unsigned long iflags;
-	int err = 0;
-
-	perf_pmu_disable(event->pmu);
-
-	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
-	/* Cycle counter has a resrvd index */
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
-		if (hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX]) {
-			pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
-			err = -EINVAL;
-			goto out;
-		}
-		hwc->idx = BB_L2CYCLE_CTR_EVENT_IDX;
-		hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX] = event;
-		set_bit(BB_L2CYCLE_CTR_EVENT_IDX,
-			(long unsigned int *)&hw_bb_l2_pmu.active_mask);
-		goto skip_ctr_loop;
-	}
-
-	for (ctr = 0; ctr < MAX_BB_L2_CTRS - 1; ctr++) {
-		if (!hw_bb_l2_pmu.events[ctr]) {
-			hwc->idx = ctr;
-			hw_bb_l2_pmu.events[ctr] = event;
-			set_bit(ctr, (long unsigned int *)
-				&hw_bb_l2_pmu.active_mask);
-			break;
-		}
-	}
-
-	if (hwc->idx < 0) {
-		err = -ENOSPC;
-		pr_err("%s: No space for event: %llx!!\n", __func__,
-		       event->attr.config);
-		goto out;
-	}
-
-skip_ctr_loop:
-
-	bb_l2_disable_counter(hwc->idx);
-
-	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
-	if (flags & PERF_EF_START)
-		bb_l2_start_counter(event, PERF_EF_RELOAD);
-
-	perf_event_update_userpage(event);
-
-	pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
-		 __func__, hwc->config_base, hwc->idx, smp_processor_id());
-out:
-	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
-	/* Resume the PMU even if this event could not be added */
-	perf_pmu_enable(event->pmu);
-
-	return err;
-}
-
-static void bb_l2_pmu_enable(struct pmu *pmu)
-{
-	unsigned long flags;
-	isb();
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-	/* Enable all counters */
-	bb_l2_pmnc_write(bb_l2_pmnc_read() | SCORPIONL2_PMNC_E);
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-}
-
-static void bb_l2_pmu_disable(struct pmu *pmu)
-{
-	unsigned long flags;
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-	/* Disable all counters */
-	bb_l2_pmnc_write(bb_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	isb();
-}
-
-static inline u32 bb_l2_get_reset_pmovsr(void)
-{
-	u32 val;
-
-	/* Read */
-	asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
-
-	/* Write to clear flags */
-	val &= 0xffffffff;
-	asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
-
-	return val;
-}
-
-static irqreturn_t bb_l2_handle_irq(int irq_num, void *dev)
-{
-	unsigned long pmovsr;
-	struct perf_sample_data data;
-	struct pt_regs *regs;
-	struct perf_event *event;
-	struct hw_perf_event *hwc;
-	int bitp;
-	int idx = 0;
-
-	pmovsr = bb_l2_get_reset_pmovsr();
-
-	if (!(pmovsr & 0xffffffff))
-		return IRQ_NONE;
-
-	regs = get_irq_regs();
-
-	perf_sample_data_init(&data, 0);
-
-	raw_spin_lock(&hw_bb_l2_pmu.lock);
-
-	while (pmovsr) {
-		bitp = __ffs(pmovsr);
-
-		if (bitp == BB_L2CYCLE_CTR_BIT)
-			idx = BB_L2CYCLE_CTR_EVENT_IDX;
-		else
-			idx = bitp;
-
-		event = hw_bb_l2_pmu.events[idx];
-
-		if (!event)
-			goto next;
-
-		if (!test_bit(idx, hw_bb_l2_pmu.active_mask))
-			goto next;
-
-		hwc = &event->hw;
-		bb_pmu_event_update(event, hwc, idx, 1);
-		data.period = event->hw.last_period;
-
-		if (!bb_pmu_event_set_period(event, hwc, idx))
-			goto next;
-
-		if (perf_event_overflow(event, 0, &data, regs))
-			bb_l2_disable_counter(hwc->idx);
-next:
-		pmovsr &= (pmovsr - 1);
-	}
-
-	raw_spin_unlock(&hw_bb_l2_pmu.lock);
-
-	irq_work_run();
-
-	return IRQ_HANDLED;
-}
-
-static atomic_t active_bb_l2_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(bb_pmu_reserve_mutex);
-
-static int bb_pmu_reserve_hardware(void)
-{
-	int i, err = -ENODEV, irq;
-
-	bb_l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
-
-	if (IS_ERR(bb_l2_pmu_device)) {
-		pr_warning("unable to reserve pmu\n");
-		return PTR_ERR(bb_l2_pmu_device);
-	}
-
-	if (bb_l2_pmu_device->num_resources < 1) {
-		pr_err("no irqs for PMUs defined\n");
-		return -ENODEV;
-	}
-
-	if (strncmp(bb_l2_pmu_device->name, "l2-arm-pmu", 6)) {
-		pr_err("Incorrect pdev reserved !\n");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < bb_l2_pmu_device->num_resources; ++i) {
-		irq = platform_get_irq(bb_l2_pmu_device, i);
-		if (irq < 0)
-			continue;
-
-		err = request_irq(irq, bb_l2_handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "bb-l2-pmu", NULL);
-		if (err) {
-			pr_warning("unable to request IRQ%d for Krait L2 perf "
-				   "counters\n", irq);
-			break;
-		}
-
-		irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
-	}
-
-	if (err) {
-		for (i = i - 1; i >= 0; --i) {
-			irq = platform_get_irq(bb_l2_pmu_device, i);
-			if (irq >= 0)
-				free_irq(irq, NULL);
-		}
-		release_pmu(bb_l2_pmu_device);
-		bb_l2_pmu_device = NULL;
-	}
-
-	return err;
-}
-
-static void bb_pmu_release_hardware(void)
-{
-	int i, irq;
-
-	for (i = bb_l2_pmu_device->num_resources - 1; i >= 0; --i) {
-		irq = platform_get_irq(bb_l2_pmu_device, i);
-		if (irq >= 0)
-			free_irq(irq, NULL);
-	}
-
-	bb_l2_pmu_disable(NULL);
-
-	release_pmu(bb_l2_pmu_device);
-	bb_l2_pmu_device = NULL;
-}
-
-static void bb_pmu_perf_event_destroy(struct perf_event *event)
-{
-	if (atomic_dec_and_mutex_lock
-	    (&active_bb_l2_events, &bb_pmu_reserve_mutex)) {
-		bb_pmu_release_hardware();
-		mutex_unlock(&bb_pmu_reserve_mutex);
-	}
-}
-
-static int bb_l2_event_init(struct perf_event *event)
-{
-	int err = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	int status = 0;
-
-	switch (event->attr.type) {
-	case PERF_TYPE_SHARED:
-		break;
-
-	default:
-		return -ENOENT;
-	}
-
-	hwc->idx = -1;
-
-	event->destroy = bb_pmu_perf_event_destroy;
-
-	if (!atomic_inc_not_zero(&active_bb_l2_events)) {
-		/* 0 active events */
-		mutex_lock(&bb_pmu_reserve_mutex);
-		err = bb_pmu_reserve_hardware();
-		mutex_unlock(&bb_pmu_reserve_mutex);
-		if (!err)
-			atomic_inc(&active_bb_l2_events);
-		else
-			return err;
-	}
-
-	hwc->config = 0;
-	hwc->event_base = 0;
-
-	/* Check if we came via perf default syms */
-	if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
-		hwc->config_base = BB_L2CYCLE_CTR_RAW_CODE;
-	else
-		hwc->config_base = event->attr.config;
-
-	/* Only one CPU can control the cycle counter */
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
-		/* Check if its already running */
-		asm volatile ("mrc p15, 3, %0, c15, c4, 6" : "=r" (status));
-		if (status == 0x2) {
-			err = -ENOSPC;
-			goto out;
-		}
-	}
-
-	if (!hwc->sample_period) {
-		hwc->sample_period = MAX_BB_L2_PERIOD;
-		hwc->last_period = hwc->sample_period;
-		local64_set(&hwc->period_left, hwc->sample_period);
-	}
-
-	pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
-
-out:
-	if (err < 0)
-		bb_pmu_perf_event_destroy(event);
-
-	return err;
-}
-
-static struct pmu bb_l2_pmu = {
-	.pmu_enable = bb_l2_pmu_enable,
-	.pmu_disable = bb_l2_pmu_disable,
-	.event_init = bb_l2_event_init,
-	.add = bb_l2_add_event,
-	.del = bb_l2_del_event,
-	.start = bb_l2_start_counter,
-	.stop = bb_l2_stop_counter,
-	.read = bb_l2_read,
-};
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
-	/* Register our own PMU here */
-	perf_pmu_register(&bb_l2_pmu, "BB L2", PERF_TYPE_SHARED);
-
-	memset(&hw_bb_l2_pmu, 0, sizeof(hw_bb_l2_pmu));
-
-	/* Avoid spurious interrupts at startup */
-	bb_l2_get_reset_pmovsr();
-
-	raw_spin_lock_init(&hw_bb_l2_pmu.lock);
-
-	/* Don't return an arm_pmu here */
-	return NULL;
-}
-#else
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
-	return NULL;
-}
-
-#endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8207f41..1896059 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -25,6 +25,7 @@
 obj-y += acpuclock.o
 obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
+obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
 obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
 
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
new file mode 100644
index 0000000..3310d92
--- /dev/null
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 2011, 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#include <linux/irq.h>
+#include <asm/pmu.h>
+#include <linux/platform_device.h>
+
+
+#define MAX_SCORPION_L2_CTRS 5
+#define SCORPION_L2CYCLE_CTR_BIT 31
+#define SCORPION_L2CYCLE_CTR_EVENT_IDX 4
+#define SCORPION_L2CYCLE_CTR_RAW_CODE 0xfe
+#define SCORPIONL2_PMNC_E       (1 << 0)	/* Enable all counters */
+#define SCORPION_L2_EVT_PREFIX 3
+#define SCORPION_MAX_L2_REG 4
+
+static u32 pmu_type;
+
+static struct arm_pmu scorpion_l2_pmu;
+
+static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
+static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
+
+static struct pmu_hw_events scorpion_l2_pmu_hw_events = {
+	.events = l2_events,
+	.used_mask = l2_used_mask,
+	.pmu_lock =
+		__RAW_SPIN_LOCK_UNLOCKED(scorpion_l2_pmu_hw_events.pmu_lock),
+};
+
+struct scorpion_l2_scorp_evt {
+	u32 evt_type;
+	u32 val;
+	u8 grp;
+	u32 evt_type_act;
+};
+
+enum scorpion_perf_types {
+	SCORPIONL2_TOTAL_BANK_REQ = 0x90,
+	SCORPIONL2_DSIDE_READ = 0x91,
+	SCORPIONL2_DSIDE_WRITE = 0x92,
+	SCORPIONL2_ISIDE_READ = 0x93,
+	SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
+	SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
+	SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
+	SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
+	SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
+	SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
+	SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
+	SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
+	SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
+	SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
+	SCORPIONL2_BARRIERS = 0x9e,
+	SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
+	SCORPIONL2_MVA_POC = 0xa0,
+	SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
+	SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
+	SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
+	SCORPIONL2_ISIDE_READ_HITS = 0xa4,
+	SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
+	SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
+	SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
+	SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
+	SCORPIONL2_L2LINE_LOCKED = 0xa9,
+	SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
+	SCORPIONL2_CACHE_MVA_POC = 0xab,
+	SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
+	SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
+	SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
+	SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
+	SCORPIONL2_PMBUS_MPAAF = 0xb0,
+	SCORPIONL2_PMBUS_MPWDAF = 0xb1,
+	SCORPIONL2_PMBUS_MPBRT = 0xb2,
+	SCORPIONL2_CPU0_GRANT = 0xb3,
+	SCORPIONL2_CPU1_GRANT = 0xb4,
+	SCORPIONL2_CPU0_NOGRANT = 0xb5,
+	SCORPIONL2_CPU1_NOGRANT = 0xb6,
+	SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
+	SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
+	SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
+	SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
+	SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
+	SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
+	SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
+	SCORPIONL2_L2EM_STREX_PASS = 0xbe,
+	SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
+	SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
+	SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
+	SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
+	SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
+	SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
+	SCORPIONL2_CPU0_CLAMPED = 0xc5,
+	SCORPIONL2_CPU1_CLAMPED = 0xc6,
+	SCORPIONL2_CPU0_WAIT = 0xc7,
+	SCORPIONL2_CPU1_WAIT = 0xc8,
+	SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
+	SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
+	SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
+	SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
+	SCORPIONL2_AXI_READ = 0xcd,
+	SCORPIONL2_AXI_WRITE = 0xce,
+
+	SCORPIONL2_1BEAT_WRITE = 0xcf,
+	SCORPIONL2_2BEAT_WRITE = 0xd0,
+	SCORPIONL2_4BEAT_WRITE = 0xd1,
+	SCORPIONL2_8BEAT_WRITE = 0xd2,
+	SCORPIONL2_12BEAT_WRITE = 0xd3,
+	SCORPIONL2_16BEAT_WRITE = 0xd4,
+	SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
+	SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
+	SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
+	SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
+	SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
+	SCORPIONL2_CSYS_READ_2BEAT = 0xda,
+	SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
+	SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
+	SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
+	SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
+	SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
+	SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
+	SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
+	SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
+	SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
+	SCORPIONL2_LDREX_REQ = 0xe4,
+	SCORPIONL2_STREX_PASS = 0xe5,
+	SCORPIONL2_STREX_FAIL = 0xe6,
+	SCORPIONL2_CPREAD = 0xe7,
+	SCORPIONL2_CPWRITE = 0xe8,
+	SCORPIONL2_BARRIER_REQ = 0xe9,
+	SCORPIONL2_AXI_READ_SLVPORT = 0xea,
+	SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
+	SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
+	SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
+	SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
+	SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
+	SCORPIONL2_SNOOPED_IC = 0xf0,
+	SCORPIONL2_SNOOPED_BP = 0xf1,
+	SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
+	SCORPIONL2_SNOOPED_TLB = 0xf3,
+	SCORPION_L2_MAX_EVT,
+};
+
+static const struct scorpion_l2_scorp_evt sc_evt[] = {
+	{SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
+	{SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
+	{SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
+	{SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
+	{SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
+	{SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
+	{SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
+	{SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
+	{SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
+	{SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
+	{SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
+	{SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
+	{SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
+	{SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
+	{SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
+	{SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
+	{SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
+	{SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
+	{SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
+	{SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
+	{SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
+	{SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
+	{SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
+	{SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
+	{SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
+	{SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
+	{SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
+	{SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
+	{SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
+	{SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
+	{SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
+	{SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
+	{SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
+
+	{SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
+	{SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
+	{SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
+	{SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
+	{SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
+	{SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
+	{SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
+	{SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
+	{SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
+	{SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
+	{SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
+	{SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
+	{SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
+	{SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
+	{SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
+	{SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
+	{SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
+	{SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
+	{SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
+
+	{SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
+	{SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
+	{SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
+	{SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
+	{SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
+	{SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
+	{SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
+	{SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
+	{SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
+	{SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
+	{SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
+	{SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
+	{SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
+	{SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
+	{SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
+	{SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
+	{SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
+	{SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
+	{SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
+	{SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
+	{SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
+	{SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
+	{SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
+	{SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
+	{SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
+	{SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
+	{SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
+
+	{SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
+	{SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
+	{SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
+	{SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
+
+	{SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
+	{SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
+	{SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
+	{SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
+	{SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
+	{SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
+};
+
+static struct pmu_hw_events *scorpion_l2_get_hw_events(void)
+{
+	return &scorpion_l2_pmu_hw_events;
+}
+static u32 scorpion_l2_read_l2pm0(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm0(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm1(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm1(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm2(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm2(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm3(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm3(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm4(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm4(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
+}
+
+struct scorpion_scorpion_access_funcs {
+	u32(*read) (void);
+	void (*write) (u32);
+	void (*pre) (void);
+	void (*post) (void);
+};
+
+struct scorpion_scorpion_access_funcs scorpion_l2_func[] = {
+	{scorpion_l2_read_l2pm0, scorpion_l2_write_l2pm0, NULL, NULL},
+	{scorpion_l2_read_l2pm1, scorpion_l2_write_l2pm1, NULL, NULL},
+	{scorpion_l2_read_l2pm2, scorpion_l2_write_l2pm2, NULL, NULL},
+	{scorpion_l2_read_l2pm3, scorpion_l2_write_l2pm3, NULL, NULL},
+	{scorpion_l2_read_l2pm4, scorpion_l2_write_l2pm4, NULL, NULL},
+};
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+
+static u32 scorpion_l2_get_columnmask(u32 setval)
+{
+	if (setval & COLMN0MASK)
+		return 0xffffff00;
+	else if (setval & COLMN1MASK)
+		return 0xffff00ff;
+	else if (setval & COLMN2MASK)
+		return 0xff00ffff;
+	else
+		return 0x80ffffff;
+}
+
+static void scorpion_l2_evt_setup(u32 gr, u32 setval)
+{
+	u32 val;
+	if (scorpion_l2_func[gr].pre)
+		scorpion_l2_func[gr].pre();
+	val = scorpion_l2_get_columnmask(setval) & scorpion_l2_func[gr].read();
+	val = val | setval;
+	scorpion_l2_func[gr].write(val);
+	if (scorpion_l2_func[gr].post)
+		scorpion_l2_func[gr].post();
+}
+
+#define SCORPION_L2_EVT_START_IDX 0x90
+#define SCORPION_L2_INV_EVTYPE 0
+
+static unsigned int get_scorpion_l2_evtinfo(unsigned int evt_type,
+				      struct scorpion_l2_scorp_evt *evtinfo)
+{
+	u32 idx;
+	u8 prefix;
+	u8 reg;
+	u8 code;
+	u8 group;
+
+	prefix = (evt_type & 0xF0000) >> 16;
+	if (prefix == SCORPION_L2_EVT_PREFIX) {
+		reg   = (evt_type & 0x0F000) >> 12;
+		code  = (evt_type & 0x00FF0) >> 4;
+		group =  evt_type & 0x0000F;
+
+		if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
+			return SCORPION_L2_INV_EVTYPE;
+
+		evtinfo->val = 0x80000000 | (code << (group * 8));
+		evtinfo->grp = reg;
+		evtinfo->evt_type_act = group | (reg << 2);
+		return evtinfo->evt_type_act;
+	}
+
+	if (evt_type < SCORPION_L2_EVT_START_IDX
+			|| evt_type >= SCORPION_L2_MAX_EVT)
+		return SCORPION_L2_INV_EVTYPE;
+
+	idx = evt_type - SCORPION_L2_EVT_START_IDX;
+
+	if (sc_evt[idx].evt_type == evt_type) {
+		evtinfo->val = sc_evt[idx].val;
+		evtinfo->grp = sc_evt[idx].grp;
+		evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+		return sc_evt[idx].evt_type_act;
+	}
+	return SCORPION_L2_INV_EVTYPE;
+}
+
+static inline void scorpion_l2_pmnc_write(unsigned long val)
+{
+	val &= 0xff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
+}
+
+static inline unsigned long scorpion_l2_pmnc_read(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_set_evcntcr(void)
+{
+	u32 val = 0x0;
+	asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
+}
+
+static inline void scorpion_l2_set_evtyper(int ctr, int val)
+{
+	/* select ctr */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
+
+	/* write into EVTYPER */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
+}
+
+static void scorpion_l2_set_evfilter_task_mode(void)
+{
+	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_set_evfilter_sys_mode(void)
+{
+	u32 filter_val = 0x000f003f;
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_enable_intenset(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_disable_intenclr(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_enable_counter(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_disable_counter(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
+	}
+}
+
+static u32 scorpion_l2_read_counter(int idx)
+{
+	u32 val;
+	unsigned long iflags;
+
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
+	} else {
+		raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* read val from counter */
+		asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
+		raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+	}
+
+	return val;
+}
+
+static void scorpion_l2_write_counter(int idx, u32 val)
+{
+	unsigned long iflags;
+
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
+	} else {
+		raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+
+		/* select counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* write val into counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
+		raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+	}
+}
+
+static void scorpion_l2_stop_counter(struct hw_perf_event *hwc, int idx)
+{
+	scorpion_l2_disable_intenclr(idx);
+	scorpion_l2_disable_counter(idx);
+	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
+			hwc->config_base, idx);
+}
+
+static void scorpion_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
+{
+	struct scorpion_l2_scorp_evt evtinfo;
+	int evtype = hwc->config_base;
+	int ev_typer;
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
+		goto out;
+
+	memset(&evtinfo, 0, sizeof(evtinfo));
+
+	ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
+
+	scorpion_l2_set_evtyper(idx, ev_typer);
+
+	scorpion_l2_set_evcntcr();
+
+	if (cpu < 0)
+		scorpion_l2_set_evfilter_task_mode();
+	else
+		scorpion_l2_set_evfilter_sys_mode();
+
+	scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
+
+out:
+
+	scorpion_l2_enable_intenset(idx);
+
+	scorpion_l2_enable_counter(idx);
+
+	raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+	     __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void scorpion_l2_disable(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	scorpion_l2_stop_counter(hwc, idx);
+
+	raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+}
+
+static int scorpion_l2_get_event_idx(struct pmu_hw_events *cpuc,
+				  struct hw_perf_event *hwc)
+{
+	int ctr = 0;
+
+	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) {
+		if (!test_and_set_bit(SCORPION_L2CYCLE_CTR_EVENT_IDX,
+					cpuc->used_mask))
+			return SCORPION_L2CYCLE_CTR_EVENT_IDX;
+	}
+
+	for (ctr = 0; ctr < MAX_SCORPION_L2_CTRS - 1; ctr++) {
+		if (!test_and_set_bit(ctr, cpuc->used_mask))
+			return ctr;
+	}
+
+	return -EAGAIN;
+}
+
+static void scorpion_l2_start(void)
+{
+	isb();
+	/* Enable all counters */
+	scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() | SCORPIONL2_PMNC_E);
+}
+
+static void scorpion_l2_stop(void)
+{
+	/* Disable all counters */
+	scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
+	isb();
+}
+
+static inline u32 scorpion_l2_get_reset_pmovsr(void)
+{
+	u32 val;
+
+	/* Read */
+	asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
+
+	/* Write to clear flags */
+	val &= 0xffffffff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
+
+	return val;
+}
+
+static irqreturn_t scorpion_l2_handle_irq(int irq_num, void *dev)
+{
+	unsigned long pmovsr;
+	struct perf_sample_data data;
+	struct pt_regs *regs;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int bitp;
+	int idx = 0;
+
+	pmovsr = scorpion_l2_get_reset_pmovsr();
+
+	if (!(pmovsr & 0xffffffff))
+		return IRQ_NONE;
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	while (pmovsr) {
+		bitp = __ffs(pmovsr);
+
+		if (bitp == SCORPION_L2CYCLE_CTR_BIT)
+			idx = SCORPION_L2CYCLE_CTR_EVENT_IDX;
+		else
+			idx = bitp;
+
+		event = scorpion_l2_pmu_hw_events.events[idx];
+
+		if (!event)
+			goto next;
+
+		if (!test_bit(idx, scorpion_l2_pmu_hw_events.used_mask))
+			goto next;
+
+		hwc = &event->hw;
+
+		armpmu_event_update(event, hwc, idx);
+
+		data.period = event->hw.last_period;
+
+		if (!armpmu_event_set_period(event, hwc, idx))
+			goto next;
+
+		if (perf_event_overflow(event, &data, regs))
+			scorpion_l2_disable_counter(hwc->idx);
+next:
+		pmovsr &= (pmovsr - 1);
+	}
+
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static int scorpion_l2_map_event(struct perf_event *event)
+{
+	if (pmu_type > 0 && pmu_type == event->attr.type)
+		return event->attr.config & 0xfffff;
+	else
+		return -ENOENT;
+}
+
+static int
+scorpion_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	return request_irq(irq, *handle_irq,
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			"scorpion-l2-armpmu", NULL);
+}
+
+static void
+scorpion_l2_pmu_generic_free_irq(int irq)
+{
+	if (irq >= 0)
+		free_irq(irq, NULL);
+}
+
+static struct arm_pmu scorpion_l2_pmu = {
+	.id		=	ARM_PERF_PMU_ID_SCORPIONMP_L2,
+	.type		=	ARM_PMU_DEVICE_L2CC,
+	.name		=	"Scorpion L2CC PMU",
+	.start		=	scorpion_l2_start,
+	.stop		=	scorpion_l2_stop,
+	.handle_irq	=	scorpion_l2_handle_irq,
+	.request_pmu_irq	= scorpion_l2_pmu_generic_request_irq,
+	.free_pmu_irq		= scorpion_l2_pmu_generic_free_irq,
+	.enable		=	scorpion_l2_enable,
+	.disable	=	scorpion_l2_disable,
+	.read_counter	=	scorpion_l2_read_counter,
+	.get_event_idx	=	scorpion_l2_get_event_idx,
+	.write_counter	=	scorpion_l2_write_counter,
+	.map_event	=	scorpion_l2_map_event,
+	.max_period	=	(1LLU << 32) - 1,
+	.get_hw_events	=	scorpion_l2_get_hw_events,
+	.num_events	=	MAX_SCORPION_L2_CTRS,
+};
+
+static int __devinit scorpion_l2_pmu_device_probe(struct platform_device *pdev)
+{
+	scorpion_l2_pmu.plat_device = pdev;
+
+	if (!armpmu_register(&scorpion_l2_pmu, "scorpion-l2", -1))
+		pmu_type = scorpion_l2_pmu.pmu.type;
+
+	return 0;
+}
+
+static struct platform_driver scorpion_l2_pmu_driver = {
+	.driver		= {
+		.name	= "l2-arm-pmu",
+	},
+	.probe		= scorpion_l2_pmu_device_probe,
+};
+
+static int __init register_scorpion_l2_pmu_driver(void)
+{
+	/* Avoid spurious interrupt if any */
+	scorpion_l2_get_reset_pmovsr();
+
+	return platform_driver_register(&scorpion_l2_pmu_driver);
+}
+device_initcall(register_scorpion_l2_pmu_driver);