1ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/* 2ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * CCI cache coherent interconnect driver 3ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 4ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Copyright (C) 2013 ARM Ltd. 5ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> 6ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 7ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * This program is free software; you can redistribute it and/or modify 8ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * it under the terms of the GNU General Public License version 2 as 9ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * published by the Free Software Foundation. 10ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 11ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * kind, whether express or implied; without even the implied warranty 13ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * GNU General Public License for more details. 15ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 16ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 17ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <linux/arm-cci.h> 18ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <linux/io.h> 19ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <linux/module.h> 20ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <linux/of_address.h> 21b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <linux/of_irq.h> 22b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <linux/of_platform.h> 23b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <linux/platform_device.h> 24ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <linux/slab.h> 25b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <linux/spinlock.h> 26ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 27ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <asm/cacheflush.h> 28b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <asm/irq_regs.h> 29b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#include <asm/pmu.h> 30ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#include <asm/smp_plat.h> 31ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 32b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define DRIVER_NAME "CCI-400" 33b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define DRIVER_NAME_PMU DRIVER_NAME " PMU" 34b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 35ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define CCI_PORT_CTRL 0x0 36ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define CCI_CTRL_STATUS 0xc 37ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 38ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define CCI_ENABLE_SNOOP_REQ 0x1 39ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define CCI_ENABLE_DVM_REQ 0x2 40ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define CCI_ENABLE_REQ (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ) 41ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 42ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistruct cci_nb_ports { 43ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi unsigned int nb_ace; 44ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi unsigned int nb_ace_lite; 45ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 46ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 47ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisienum cci_ace_port_type { 48ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ACE_INVALID_PORT = 0x0, 49ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ACE_PORT, 50ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ACE_LITE_PORT, 51ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 52ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 53ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistruct cci_ace_port { 54ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi void __iomem *base; 5562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre unsigned long phys; 56ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi enum cci_ace_port_type type; 57ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi struct device_node *dn; 58ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 59ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 60ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic struct cci_ace_port *ports; 61ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic unsigned int nb_cci_ports; 62ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 63ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic void __iomem *cci_ctrl_base; 6462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitrestatic unsigned long cci_ctrl_phys; 65ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 66b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#ifdef CONFIG_HW_PERF_EVENTS 67b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 68b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMCR 0x0100 69b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PID2 0x0fe8 70b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 71b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMCR_CEN 0x00000001 72b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMCR_NCNT_MASK 0x0000f800 73b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMCR_NCNT_SHIFT 11 74b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 75b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PID2_REV_MASK 0xf0 76b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PID2_REV_SHIFT 4 77b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 78b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal/* Port ids */ 79b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_S0 0 80b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_S1 1 81b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_S2 2 82b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_S3 3 83b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_S4 4 84b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_M0 5 85b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_M1 6 86b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PORT_M2 7 87b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 88b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R0 0 89b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R1 1 906fb0c4a74239416b572f088a827d5ff783902380Punit Agrawal#define CCI_REV_R1_PX 5 91b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 92b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_EVT_SEL 0x000 93b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CNTR 0x004 94b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CNTR_CTRL 0x008 95b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_OVRFLW 0x00c 96b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 97b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_OVRFLW_FLAG 1 98b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 99b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CNTR_BASE(idx) ((idx) * SZ_4K) 100b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 101b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal/* 102b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * Instead of an event id to monitor CCI cycles, a dedicated counter is 103b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * provided. Use 0xff to represent CCI cycles and hope that no future revisions 104b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * make use of this event in hardware. 105b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 106b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalenum cci400_perf_events { 107b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal CCI_PMU_CYCLES = 0xff 108b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 109b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 110b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_EVENT_MASK 0xff 111b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_EVENT_SOURCE(event) ((event >> 5) & 0x7) 112b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_EVENT_CODE(event) (event & 0x1f) 113b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 114b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */ 115b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 116b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CYCLE_CNTR_IDX 0 117b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CNTR0_IDX 1 118b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_PMU_CNTR_LAST(cci_pmu) (CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1) 119b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 120b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal/* 121b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8 122b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * ports and bits 4:0 are event codes. There are different event codes 123b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * associated with each port type. 124b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * 125b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * Additionally, the range of events associated with the port types changed 126b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * between Rev0 and Rev1. 127b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * 128b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * The constants below define the range of valid codes for each port type for 129b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * the different revisions and are used to validate the event to be monitored. 130b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 131b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 132b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R0_SLAVE_PORT_MIN_EV 0x00 133b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R0_SLAVE_PORT_MAX_EV 0x13 134b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R0_MASTER_PORT_MIN_EV 0x14 135b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R0_MASTER_PORT_MAX_EV 0x1a 136b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 137b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R1_SLAVE_PORT_MIN_EV 0x00 138b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R1_SLAVE_PORT_MAX_EV 0x14 139b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00 140b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11 141b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 142b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstruct pmu_port_event_ranges { 143b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 slave_min; 144b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 slave_max; 145b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 master_min; 146b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 master_max; 147b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 148b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 149b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct pmu_port_event_ranges port_event_range[] = { 150b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal [CCI_REV_R0] = { 151b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .slave_min = CCI_REV_R0_SLAVE_PORT_MIN_EV, 152b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .slave_max = CCI_REV_R0_SLAVE_PORT_MAX_EV, 153b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .master_min = CCI_REV_R0_MASTER_PORT_MIN_EV, 154b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .master_max = CCI_REV_R0_MASTER_PORT_MAX_EV, 155b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }, 156b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal [CCI_REV_R1] = { 157b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .slave_min = CCI_REV_R1_SLAVE_PORT_MIN_EV, 158b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .slave_max = CCI_REV_R1_SLAVE_PORT_MAX_EV, 159b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .master_min = CCI_REV_R1_MASTER_PORT_MIN_EV, 160b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .master_max = CCI_REV_R1_MASTER_PORT_MAX_EV, 161b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }, 162b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 163b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 164dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal/* 165dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal * Export different PMU names for the different revisions so userspace knows 166dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal * because the event ids are different 167dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal */ 168dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawalstatic char *const pmu_names[] = { 169dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal [CCI_REV_R0] = "CCI_400", 170dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal [CCI_REV_R1] = "CCI_400_r1", 171dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal}; 172dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal 173b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstruct cci_pmu_drv_data { 174b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal void __iomem *base; 175b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu; 176b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int nr_irqs; 177b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int irqs[CCI_PMU_MAX_HW_EVENTS]; 178b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long active_irqs; 179b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct perf_event *events[CCI_PMU_MAX_HW_EVENTS]; 180b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)]; 181b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_port_event_ranges *port_ranges; 182b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_hw_events hw_events; 183b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 184b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct cci_pmu_drv_data *pmu; 185b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 186b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) 187b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 188b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int i; 189b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 190b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (i = 0; i < nr_irqs; i++) 191b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (irq == irqs[i]) 192b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return true; 193b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 194b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return false; 195b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 196b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 197b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int probe_cci_revision(void) 198b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 199b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int rev; 200b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK; 201b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal rev >>= CCI_PID2_REV_SHIFT; 202b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 2036fb0c4a74239416b572f088a827d5ff783902380Punit Agrawal if (rev < CCI_REV_R1_PX) 204b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return CCI_REV_R0; 2056fb0c4a74239416b572f088a827d5ff783902380Punit Agrawal else 206b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return CCI_REV_R1; 207b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 208b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 209b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct pmu_port_event_ranges *port_range_by_rev(void) 210b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 211b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int rev = probe_cci_revision(); 212b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 213b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return &port_event_range[rev]; 214b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 215b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 216b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_is_valid_slave_event(u8 ev_code) 217b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 218b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return pmu->port_ranges->slave_min <= ev_code && 219b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal ev_code <= pmu->port_ranges->slave_max; 220b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 221b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 222b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_is_valid_master_event(u8 ev_code) 223b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 224b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return pmu->port_ranges->master_min <= ev_code && 225b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal ev_code <= pmu->port_ranges->master_max; 226b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 227b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 228b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_validate_hw_event(u8 hw_event) 229b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 230b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event); 231b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 ev_code = CCI_PMU_EVENT_CODE(hw_event); 232b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 233b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal switch (ev_source) { 234b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_S0: 235b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_S1: 236b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_S2: 237b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_S3: 238b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_S4: 239b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Slave Interface */ 240b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (pmu_is_valid_slave_event(ev_code)) 241b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return hw_event; 242b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal break; 243b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_M0: 244b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_M1: 245b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal case CCI_PORT_M2: 246b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Master Interface */ 247b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (pmu_is_valid_master_event(ev_code)) 248b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return hw_event; 249b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal break; 250b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 251b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 252b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENOENT; 253b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 254b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 255b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_is_valid_counter(struct arm_pmu *cci_pmu, int idx) 256b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 257b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return CCI_PMU_CYCLE_CNTR_IDX <= idx && 258b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal idx <= CCI_PMU_CNTR_LAST(cci_pmu); 259b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 260b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 261b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic u32 pmu_read_register(int idx, unsigned int offset) 262b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 263b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset); 264b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 265b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 266b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_write_register(u32 value, int idx, unsigned int offset) 267b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 268b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset); 269b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 270b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 271b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_disable_counter(int idx) 272b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 273b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL); 274b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 275b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 276b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_enable_counter(int idx) 277b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 278b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL); 279b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 280b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 281b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_set_event(int idx, unsigned long event) 282b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 283b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal event &= CCI_PMU_EVENT_MASK; 284b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_write_register(event, idx, CCI_PMU_EVT_SEL); 285b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 286b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 287b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic u32 pmu_get_max_counters(void) 288b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 289b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) & 290b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT; 291b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 292b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* add 1 for cycle counter */ 293b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return n_cnts + 1; 294b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 295b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 296b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct pmu_hw_events *pmu_get_hw_events(void) 297b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 298b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return &pmu->hw_events; 299b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 300b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 301b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_get_event_idx(struct pmu_hw_events *hw, struct perf_event *event) 302b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 303b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); 304b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_event = &event->hw; 305b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long cci_event = hw_event->config_base & CCI_PMU_EVENT_MASK; 306b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx; 307b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 308b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (cci_event == CCI_PMU_CYCLES) { 309b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask)) 310b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -EAGAIN; 311b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 312b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return CCI_PMU_CYCLE_CNTR_IDX; 313b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 314b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 315b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx) 316b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!test_and_set_bit(idx, hw->used_mask)) 317b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return idx; 318b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 319b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* No counters available */ 320b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -EAGAIN; 321b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 322b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 323b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_map_event(struct perf_event *event) 324b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 325b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int mapping; 326b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u8 config = event->attr.config & CCI_PMU_EVENT_MASK; 327b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 328b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (event->attr.type < PERF_TYPE_MAX) 329b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENOENT; 330b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 331b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (config == CCI_PMU_CYCLES) 332b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal mapping = config; 333b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal else 334b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal mapping = pmu_validate_hw_event(config); 335b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 336b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return mapping; 337b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 338b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 339b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int pmu_request_irq(struct arm_pmu *cci_pmu, irq_handler_t handler) 340b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 341b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int i; 342b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct platform_device *pmu_device = cci_pmu->plat_device; 343b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 344b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (unlikely(!pmu_device)) 345b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENODEV; 346b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 347b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (pmu->nr_irqs < 1) { 348b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n"); 349b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENODEV; 350b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 351b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 352b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* 353b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * Register all available CCI PMU interrupts. In the interrupt handler 354b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * we iterate over the counters checking for interrupt source (the 355b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * overflowing counter) and clear it. 356b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * 357b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * This should allow handling of non-unique interrupt for the counters. 358b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 359b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (i = 0; i < pmu->nr_irqs; i++) { 360b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED, 361b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal "arm-cci-pmu", cci_pmu); 362b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (err) { 363b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n", 364b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->irqs[i]); 365b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return err; 366b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 367b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 368b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal set_bit(i, &pmu->active_irqs); 369b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 370b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 371b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return 0; 372b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 373b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 374b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic irqreturn_t pmu_handle_irq(int irq_num, void *dev) 375b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 376b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long flags; 377b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = (struct arm_pmu *)dev; 378b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_hw_events *events = cci_pmu->get_hw_events(); 379b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct perf_sample_data data; 380b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pt_regs *regs; 381b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx, handled = IRQ_NONE; 382b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 383b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_lock_irqsave(&events->pmu_lock, flags); 384b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal regs = get_irq_regs(); 385b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* 386b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * Iterate over counters and update the corresponding perf events. 387b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * This should work regardless of whether we have per-counter overflow 388b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * interrupt or a combined overflow interrupt. 389b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 390b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) { 391b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct perf_event *event = events->events[idx]; 392b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_counter; 393b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 394b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!event) 395b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal continue; 396b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 397b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal hw_counter = &event->hw; 398b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 399b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Did this counter overflow? */ 400fc5130de8309727540de7cae0199764af34b0919Himangi Saraogi if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) & 401fc5130de8309727540de7cae0199764af34b0919Himangi Saraogi CCI_PMU_OVRFLW_FLAG)) 402b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal continue; 403b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 404b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW); 405b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 406b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal handled = IRQ_HANDLED; 407b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 408b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal armpmu_event_update(event); 409b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal perf_sample_data_init(&data, 0, hw_counter->last_period); 410b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!armpmu_event_set_period(event)) 411b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal continue; 412b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 413b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (perf_event_overflow(event, &data, regs)) 414b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal cci_pmu->disable(event); 415b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 416b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 417b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 418b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return IRQ_RETVAL(handled); 419b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 420b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 421b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_free_irq(struct arm_pmu *cci_pmu) 422b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 423b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int i; 424b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 425b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (i = 0; i < pmu->nr_irqs; i++) { 426b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!test_and_clear_bit(i, &pmu->active_irqs)) 427b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal continue; 428b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 429b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal free_irq(pmu->irqs[i], cci_pmu); 430b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 431b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 432b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 433b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_enable_event(struct perf_event *event) 434b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 435b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long flags; 436b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); 437b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_hw_events *events = cci_pmu->get_hw_events(); 438b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_counter = &event->hw; 439b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx = hw_counter->idx; 440b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 441b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) { 442b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); 443b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return; 444b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 445b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 446b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_lock_irqsave(&events->pmu_lock, flags); 447b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 448b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Configure the event to count, unless you are counting cycles */ 449b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (idx != CCI_PMU_CYCLE_CNTR_IDX) 450b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_set_event(idx, hw_counter->config_base); 451b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 452b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_enable_counter(idx); 453b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 454b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 455b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 456b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 457b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_disable_event(struct perf_event *event) 458b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 459b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); 460b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_counter = &event->hw; 461b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx = hw_counter->idx; 462b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 463b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) { 464b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); 465b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return; 466b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 467b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 468b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_disable_counter(idx); 469b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 470b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 471b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_start(struct arm_pmu *cci_pmu) 472b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 473b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u32 val; 474b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long flags; 475b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_hw_events *events = cci_pmu->get_hw_events(); 476b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 477b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_lock_irqsave(&events->pmu_lock, flags); 478b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 479b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Enable all the PMU counters. */ 480b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal val = readl_relaxed(cci_ctrl_base + CCI_PMCR) | CCI_PMCR_CEN; 481b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal writel(val, cci_ctrl_base + CCI_PMCR); 482b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 483b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 484b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 485b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 486b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_stop(struct arm_pmu *cci_pmu) 487b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 488b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u32 val; 489b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal unsigned long flags; 490b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct pmu_hw_events *events = cci_pmu->get_hw_events(); 491b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 492b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_lock_irqsave(&events->pmu_lock, flags); 493b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 494b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* Disable all the PMU counters. */ 495b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal val = readl_relaxed(cci_ctrl_base + CCI_PMCR) & ~CCI_PMCR_CEN; 496b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal writel(val, cci_ctrl_base + CCI_PMCR); 497b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 498b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 499b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 500b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 501b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic u32 pmu_read_counter(struct perf_event *event) 502b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 503b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); 504b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_counter = &event->hw; 505b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx = hw_counter->idx; 506b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal u32 value; 507b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 508b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) { 509b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); 510b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return 0; 511b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 512b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal value = pmu_read_register(idx, CCI_PMU_CNTR); 513b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 514b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return value; 515b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 516b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 517b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void pmu_write_counter(struct perf_event *event, u32 value) 518b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 519b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); 520b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct hw_perf_event *hw_counter = &event->hw; 521b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int idx = hw_counter->idx; 522b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 523b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) 524b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); 525b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal else 526b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu_write_register(value, idx, CCI_PMU_CNTR); 527b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 528b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 529b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int cci_pmu_init(struct arm_pmu *cci_pmu, struct platform_device *pdev) 530b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 531b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal *cci_pmu = (struct arm_pmu){ 532dc4409c0062d7e40fe523abc06310281ba666369Punit Agrawal .name = pmu_names[probe_cci_revision()], 533b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .max_period = (1LLU << 32) - 1, 534b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .get_hw_events = pmu_get_hw_events, 535b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .get_event_idx = pmu_get_event_idx, 536b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .map_event = pmu_map_event, 537b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .request_irq = pmu_request_irq, 538b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .handle_irq = pmu_handle_irq, 539b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .free_irq = pmu_free_irq, 540b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .enable = pmu_enable_event, 541b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .disable = pmu_disable_event, 542b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .start = pmu_start, 543b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .stop = pmu_stop, 544b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .read_counter = pmu_read_counter, 545b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .write_counter = pmu_write_counter, 546b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }; 547b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 548b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal cci_pmu->plat_device = pdev; 549b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal cci_pmu->num_events = pmu_get_max_counters(); 550b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 551b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return armpmu_register(cci_pmu, -1); 552b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 553b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 554b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic const struct of_device_id arm_cci_pmu_matches[] = { 555b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal { 556b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .compatible = "arm,cci-400-pmu", 557b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }, 558b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal {}, 559b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 560b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 561b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int cci_pmu_probe(struct platform_device *pdev) 562b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 563b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal struct resource *res; 564b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int i, ret, irq; 565b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 566b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); 567b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!pmu) 568b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENOMEM; 569b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 570b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 571b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->base = devm_ioremap_resource(&pdev->dev, res); 572fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun if (IS_ERR(pmu->base)) 573fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun return -ENOMEM; 574b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 575b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* 576b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * CCI PMU has 5 overflow signals - one per counter; but some may be tied 577b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * together to a common interrupt. 578b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 579b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->nr_irqs = 0; 580b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) { 581b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal irq = platform_get_irq(pdev, i); 582b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (irq < 0) 583b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal break; 584b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 585b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs)) 586b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal continue; 587b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 588b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->irqs[pmu->nr_irqs++] = irq; 589b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 590b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 591b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal /* 592b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * Ensure that the device tree has as many interrupts as the number 593b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal * of counters. 594b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal */ 595b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (i < CCI_PMU_MAX_HW_EVENTS) { 596b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n", 597b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal i, CCI_PMU_MAX_HW_EVENTS); 598fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun return -EINVAL; 599b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 600b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 601b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->port_ranges = port_range_by_rev(); 602b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!pmu->port_ranges) { 603b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal dev_warn(&pdev->dev, "CCI PMU version not supported\n"); 604fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun return -EINVAL; 605b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal } 606b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 607b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*(pmu->cci_pmu)), GFP_KERNEL); 608fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun if (!pmu->cci_pmu) 609fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun return -ENOMEM; 610b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 611b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->hw_events.events = pmu->events; 612b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal pmu->hw_events.used_mask = pmu->used_mask; 613b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal raw_spin_lock_init(&pmu->hw_events.pmu_lock); 614b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 615b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal ret = cci_pmu_init(pmu->cci_pmu, pdev); 616b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (ret) 617fee4f2c66a3b0f0e97e16b3084e8c4151ae9196fWei Yongjun return ret; 618b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 619b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return 0; 620b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 621b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 622b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int cci_platform_probe(struct platform_device *pdev) 623b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 624b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (!cci_probed()) 625b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return -ENODEV; 626b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 627b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 628b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 629b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 630b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#endif /* CONFIG_HW_PERF_EVENTS */ 631b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 632ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistruct cpu_port { 633ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi u64 mpidr; 634ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi u32 port; 635ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 63662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 637ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/* 638ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Use the port MSB as valid flag, shift can be made dynamic 639ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * by computing number of bits required for port indexes. 640ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Code disabling CCI cpu ports runs with D-cache invalidated 641ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * and SCTLR bit clear so data accesses must be kept to a minimum 642ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * to improve performance; for now shift is left static to 643ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * avoid one more data access while disabling the CCI port. 644ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 645ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define PORT_VALID_SHIFT 31 646ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi#define PORT_VALID (0x1 << PORT_VALID_SHIFT) 647ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 648ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic inline void init_cpu_port(struct cpu_port *port, u32 index, u64 mpidr) 649ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 650ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi port->port = PORT_VALID | index; 651ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi port->mpidr = mpidr; 652ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 653ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 654ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic inline bool cpu_port_is_valid(struct cpu_port *port) 655ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 656ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return !!(port->port & PORT_VALID); 657ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 658ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 659ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic inline bool cpu_port_match(struct cpu_port *port, u64 mpidr) 660ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 661ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return port->mpidr == (mpidr & MPIDR_HWID_BITMASK); 662ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 663ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 664ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic struct cpu_port cpu_port[NR_CPUS]; 665ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 666ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/** 667ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * __cci_ace_get_port - Function to retrieve the port index connected to 668ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * a cpu or device. 669ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 670ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @dn: device node of the device to look-up 671ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @type: port type 672ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 673ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Return value: 674ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * - CCI port index if success 675ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * - -ENODEV if failure 676ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 677ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic int __cci_ace_get_port(struct device_node *dn, int type) 678ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 679ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi int i; 680ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi bool ace_match; 681ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi struct device_node *cci_portn; 682ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 683ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_portn = of_parse_phandle(dn, "cci-control-port", 0); 684ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi for (i = 0; i < nb_cci_ports; i++) { 685ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ace_match = ports[i].type == type; 686ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (ace_match && cci_portn == ports[i].dn) 687ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return i; 688ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 689ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 690ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 691ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 692ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisiint cci_ace_get_port(struct device_node *dn) 693ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 694ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return __cci_ace_get_port(dn, ACE_LITE_PORT); 695ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 696ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiEXPORT_SYMBOL_GPL(cci_ace_get_port); 697ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 698b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic void cci_ace_init_ports(void) 699ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 70078b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha int port, cpu; 70178b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha struct device_node *cpun; 702ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 703ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi /* 704ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Port index look-up speeds up the function disabling ports by CPU, 705ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * since the logical to port index mapping is done once and does 706ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * not change after system boot. 707ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * The stashed index array is initialized for all possible CPUs 708ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * at probe time. 709ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 71078b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha for_each_possible_cpu(cpu) { 71178b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha /* too early to use cpu->of_node */ 71278b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha cpun = of_get_cpu_node(cpu, NULL); 713ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 71478b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha if (WARN(!cpun, "Missing cpu device node\n")) 715ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 71678b4d6e0fd2695da3019c86133444578d1ceeed3Sudeep KarkadaNagesha 717ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi port = __cci_ace_get_port(cpun, ACE_PORT); 718ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (port < 0) 719ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 720ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 721ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi init_cpu_port(&cpu_port[cpu], port, cpu_logical_map(cpu)); 722ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 723ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 724ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi for_each_possible_cpu(cpu) { 725ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi WARN(!cpu_port_is_valid(&cpu_port[cpu]), 726ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi "CPU %u does not have an associated CCI port\n", 727ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cpu); 728ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 729ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 730ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/* 731ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Functions to enable/disable a CCI interconnect slave port 732ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 733ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * They are called by low-level power management code to disable slave 734ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * interfaces snoops and DVM broadcast. 735ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Since they may execute with cache data allocation disabled and 736ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * after the caches have been cleaned and invalidated the functions provide 737ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * no explicit locking since they may run with D-cache disabled, so normal 738ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * cacheable kernel locks based on ldrex/strex may not work. 739ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Locking has to be provided by BSP implementations to ensure proper 740ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * operations. 741ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 742ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 743ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/** 744ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * cci_port_control() - function to control a CCI port 745ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 746ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @port: index of the port to setup 747ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @enable: if true enables the port, if false disables it 748ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 749ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic void notrace cci_port_control(unsigned int port, bool enable) 750ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 751ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi void __iomem *base = ports[port].base; 752ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 753ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi writel_relaxed(enable ? CCI_ENABLE_REQ : 0, base + CCI_PORT_CTRL); 754ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi /* 755ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * This function is called from power down procedures 756ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * and must not execute any instruction that might 757ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * cause the processor to be put in a quiescent state 758ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * (eg wfi). Hence, cpu_relax() can not be added to this 759ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * read loop to optimize power, since it might hide possibly 760ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * disruptive operations. 761ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 762ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi while (readl_relaxed(cci_ctrl_base + CCI_CTRL_STATUS) & 0x1) 763ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ; 764ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 765ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 766ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/** 767ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * cci_disable_port_by_cpu() - function to disable a CCI port by CPU 768ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * reference 769ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 770ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @mpidr: mpidr of the CPU whose CCI port should be disabled 771ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 772ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Disabling a CCI port for a CPU implies disabling the CCI port 773ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * controlling that CPU cluster. Code disabling CPU CCI ports 774ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * must make sure that the CPU running the code is the last active CPU 775ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * in the cluster ie all other CPUs are quiescent in a low power state. 776ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 777ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Return: 778ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 0 on success 779ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * -ENODEV on port look-up failure 780ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 781ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisiint notrace cci_disable_port_by_cpu(u64 mpidr) 782ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 783ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi int cpu; 784ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi bool is_valid; 785ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi for (cpu = 0; cpu < nr_cpu_ids; cpu++) { 786ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi is_valid = cpu_port_is_valid(&cpu_port[cpu]); 787ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (is_valid && cpu_port_match(&cpu_port[cpu], mpidr)) { 788ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_port_control(cpu_port[cpu].port, false); 789ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return 0; 790ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 791ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 792ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 793ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 794ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiEXPORT_SYMBOL_GPL(cci_disable_port_by_cpu); 795ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 796ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/** 79762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * cci_enable_port_for_self() - enable a CCI port for calling CPU 79862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * 79962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * Enabling a CCI port for the calling CPU implies enabling the CCI 80062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * port controlling that CPU's cluster. Caller must make sure that the 80162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * CPU running the code is the first active CPU in the cluster and all 80262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * other CPUs are quiescent in a low power state or waiting for this CPU 80362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * to complete the CCI initialization. 80462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * 80562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * Because this is called when the MMU is still off and with no stack, 80662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * the code must be position independent and ideally rely on callee 80762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * clobbered registers only. To achieve this we must code this function 80862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * entirely in assembler. 80962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * 81062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * On success this returns with the proper CCI port enabled. In case of 81162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * any failure this never returns as the inability to enable the CCI is 81262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre * fatal and there is no possible recovery at this stage. 81362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre */ 81462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitreasmlinkage void __naked cci_enable_port_for_self(void) 81562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre{ 81662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre asm volatile ("\n" 817f49024926236068bc3fe6848aaf87b914049013aArnd Bergmann" .arch armv7-a\n" 81862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" mrc p15, 0, r0, c0, c0, 5 @ get MPIDR value \n" 81962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" and r0, r0, #"__stringify(MPIDR_HWID_BITMASK)" \n" 82062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" adr r1, 5f \n" 82162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r2, [r1] \n" 82262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" add r1, r1, r2 @ &cpu_port \n" 82362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" add ip, r1, %[sizeof_cpu_port] \n" 82462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 82562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* Loop over the cpu_port array looking for a matching MPIDR */ 82662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"1: ldr r2, [r1, %[offsetof_cpu_port_mpidr_lsb]] \n" 82762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" cmp r2, r0 @ compare MPIDR \n" 82862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" bne 2f \n" 82962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 83062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* Found a match, now test port validity */ 83162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r3, [r1, %[offsetof_cpu_port_port]] \n" 83262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" tst r3, #"__stringify(PORT_VALID)" \n" 83362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" bne 3f \n" 83462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 83562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* no match, loop with the next cpu_port entry */ 83662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"2: add r1, r1, %[sizeof_struct_cpu_port] \n" 83762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" cmp r1, ip @ done? \n" 83862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" blo 1b \n" 83962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 84062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* CCI port not found -- cheaply try to stall this CPU */ 84162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"cci_port_not_found: \n" 84262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" wfi \n" 84362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" wfe \n" 84462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" b cci_port_not_found \n" 84562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 84662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* Use matched port index to look up the corresponding ports entry */ 84762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"3: bic r3, r3, #"__stringify(PORT_VALID)" \n" 84862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" adr r0, 6f \n" 84962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldmia r0, {r1, r2} \n" 85062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" sub r1, r1, r0 @ virt - phys \n" 85162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r0, [r0, r2] @ *(&ports) \n" 85262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" mov r2, %[sizeof_struct_ace_port] \n" 85362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" mla r0, r2, r3, r0 @ &ports[index] \n" 85462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" sub r0, r0, r1 @ virt_to_phys() \n" 85562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 85662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* Enable the CCI port */ 85762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r0, [r0, %[offsetof_port_phys]] \n" 858fdb07aee0b2b9d7d1893c97f5ce79ec355caaf1fVictor Kamensky" mov r3, %[cci_enable_req]\n" 85962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" str r3, [r0, #"__stringify(CCI_PORT_CTRL)"] \n" 86062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 86162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre /* poll the status reg for completion */ 86262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" adr r1, 7f \n" 86362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r0, [r1] \n" 86462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" ldr r0, [r0, r1] @ cci_ctrl_base \n" 86562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"4: ldr r1, [r0, #"__stringify(CCI_CTRL_STATUS)"] \n" 866fdb07aee0b2b9d7d1893c97f5ce79ec355caaf1fVictor Kamensky" tst r1, %[cci_control_status_bits] \n" 86762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" bne 4b \n" 86862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 86962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" mov r0, #0 \n" 87062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" bx lr \n" 87162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 87262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" .align 2 \n" 87362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"5: .word cpu_port - . \n" 87462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"6: .word . \n" 87562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre" .word ports - 6b \n" 87662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre"7: .word cci_ctrl_phys - . \n" 87762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre : : 87862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [sizeof_cpu_port] "i" (sizeof(cpu_port)), 879fdb07aee0b2b9d7d1893c97f5ce79ec355caaf1fVictor Kamensky [cci_enable_req] "i" cpu_to_le32(CCI_ENABLE_REQ), 880fdb07aee0b2b9d7d1893c97f5ce79ec355caaf1fVictor Kamensky [cci_control_status_bits] "i" cpu_to_le32(1), 88162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre#ifndef __ARMEB__ 88262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)), 88362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre#else 88462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)+4), 88562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre#endif 88662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [offsetof_cpu_port_port] "i" (offsetof(struct cpu_port, port)), 88762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)), 88862158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)), 88962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) ); 89062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 89162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre unreachable(); 89262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre} 89362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre 89462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre/** 895ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * __cci_control_port_by_device() - function to control a CCI port by device 896ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * reference 897ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 898ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @dn: device node pointer of the device whose CCI port should be 899ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * controlled 900ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @enable: if true enables the port, if false disables it 901ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 902ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Return: 903ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 0 on success 904ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * -ENODEV on port look-up failure 905ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 906ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisiint notrace __cci_control_port_by_device(struct device_node *dn, bool enable) 907ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 908ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi int port; 909ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 910ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!dn) 911ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 912ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 913ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi port = __cci_ace_get_port(dn, ACE_LITE_PORT); 914ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (WARN_ONCE(port < 0, "node %s ACE lite port look-up failure\n", 915ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi dn->full_name)) 916ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 917ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_port_control(port, enable); 918ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return 0; 919ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 920ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiEXPORT_SYMBOL_GPL(__cci_control_port_by_device); 921ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 922ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/** 923ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * __cci_control_port_by_index() - function to control a CCI port by port index 924ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 925ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @port: port index previously retrieved with cci_ace_get_port() 926ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * @enable: if true enables the port, if false disables it 927ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 928ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Return: 929ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * 0 on success 930ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * -ENODEV on port index out of range 931ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * -EPERM if operation carried out on an ACE PORT 932ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 933ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisiint notrace __cci_control_port_by_index(u32 port, bool enable) 934ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 935ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (port >= nb_cci_ports || ports[port].type == ACE_INVALID_PORT) 936ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 937ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi /* 938ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * CCI control for ports connected to CPUS is extremely fragile 939ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * and must be made to go through a specific and controlled 940ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * interface (ie cci_disable_port_by_cpu(); control by general purpose 941ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * indexing is therefore disabled for ACE ports. 942ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 943ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (ports[port].type == ACE_PORT) 944ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -EPERM; 945ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 946ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_port_control(port, enable); 947ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return 0; 948ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 949ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiEXPORT_SYMBOL_GPL(__cci_control_port_by_index); 950ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 951ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic const struct cci_nb_ports cci400_ports = { 952ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi .nb_ace = 2, 953ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi .nb_ace_lite = 3 954ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 955ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 956ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic const struct of_device_id arm_cci_matches[] = { 957ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi {.compatible = "arm,cci-400", .data = &cci400_ports }, 958ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi {}, 959ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 960ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 961ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic const struct of_device_id arm_cci_ctrl_if_matches[] = { 962ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi {.compatible = "arm,cci-400-ctrl-if", }, 963ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi {}, 964ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi}; 965ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 966b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int cci_probe(void) 967ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 968ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi struct cci_nb_ports const *cci_config; 969ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi int ret, i, nb_ace = 0, nb_ace_lite = 0; 970ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi struct device_node *np, *cp; 97162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre struct resource res; 972ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi const char *match_str; 973ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi bool is_ace; 974ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 975ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi np = of_find_matching_node(NULL, arm_cci_matches); 976ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!np) 977ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 978ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 979ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_config = of_match_node(arm_cci_matches, np)->data; 980ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!cci_config) 981ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENODEV; 982ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 983ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite; 984ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 9857c762036e2480bfd43e62ed872b82e372fe92474Lorenzo Pieralisi ports = kcalloc(nb_cci_ports, sizeof(*ports), GFP_KERNEL); 986ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!ports) 987ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return -ENOMEM; 988ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 98962158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre ret = of_address_to_resource(np, 0, &res); 99062158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre if (!ret) { 99162158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre cci_ctrl_base = ioremap(res.start, resource_size(&res)); 99262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre cci_ctrl_phys = res.start; 99362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre } 99462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre if (ret || !cci_ctrl_base) { 995ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi WARN(1, "unable to ioremap CCI ctrl\n"); 996ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ret = -ENXIO; 997ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi goto memalloc_err; 998ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 999ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1000ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi for_each_child_of_node(np, cp) { 1001ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!of_match_node(arm_cci_ctrl_if_matches, cp)) 1002ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1003ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1004ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi i = nb_ace + nb_ace_lite; 1005ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1006ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (i >= nb_cci_ports) 1007ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi break; 1008ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1009ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (of_property_read_string(cp, "interface-type", 1010ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi &match_str)) { 1011ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi WARN(1, "node %s missing interface-type property\n", 1012ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cp->full_name); 1013ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1014ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 1015ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi is_ace = strcmp(match_str, "ace") == 0; 1016ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (!is_ace && strcmp(match_str, "ace-lite")) { 1017ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi WARN(1, "node %s containing invalid interface-type property, skipping it\n", 1018ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cp->full_name); 1019ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1020ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 1021ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 102262158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre ret = of_address_to_resource(cp, 0, &res); 102362158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre if (!ret) { 102462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre ports[i].base = ioremap(res.start, resource_size(&res)); 102562158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre ports[i].phys = res.start; 102662158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre } 102762158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre if (ret || !ports[i].base) { 1028ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi WARN(1, "unable to ioremap CCI port %d\n", i); 1029ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1030ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 1031ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1032ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (is_ace) { 1033ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (WARN_ON(nb_ace >= cci_config->nb_ace)) 1034ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1035ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ports[i].type = ACE_PORT; 1036ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ++nb_ace; 1037ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } else { 1038ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (WARN_ON(nb_ace_lite >= cci_config->nb_ace_lite)) 1039ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi continue; 1040ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ports[i].type = ACE_LITE_PORT; 1041ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ++nb_ace_lite; 1042ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 1043ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi ports[i].dn = cp; 1044ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi } 1045ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1046ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi /* initialize a stashed array of ACE ports to speed-up look-up */ 1047ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_ace_init_ports(); 1048ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1049ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi /* 1050ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * Multi-cluster systems may need this data when non-coherent, during 1051ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * cluster power-up/power-down. Make sure it reaches main memory. 1052ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 1053ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi sync_cache_w(&cci_ctrl_base); 105462158f817ad3e0368480b8e9480be34bffd8c74aNicolas Pitre sync_cache_w(&cci_ctrl_phys); 1055ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi sync_cache_w(&ports); 1056ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi sync_cache_w(&cpu_port); 1057ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); 1058ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi pr_info("ARM CCI driver probed\n"); 1059ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return 0; 1060ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1061ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisimemalloc_err: 1062ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1063ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi kfree(ports); 1064ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return ret; 1065ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 1066ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1067ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic int cci_init_status = -EAGAIN; 1068ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisistatic DEFINE_MUTEX(cci_probing); 1069ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1070b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int cci_init(void) 1071ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 1072ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (cci_init_status != -EAGAIN) 1073ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return cci_init_status; 1074ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1075ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi mutex_lock(&cci_probing); 1076ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi if (cci_init_status == -EAGAIN) 1077ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi cci_init_status = cci_probe(); 1078ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi mutex_unlock(&cci_probing); 1079ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return cci_init_status; 1080ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 1081ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1082b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#ifdef CONFIG_HW_PERF_EVENTS 1083b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct platform_driver cci_pmu_driver = { 1084b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .driver = { 1085b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .name = DRIVER_NAME_PMU, 1086b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .of_match_table = arm_cci_pmu_matches, 1087b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }, 1088b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .probe = cci_pmu_probe, 1089b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 1090b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1091b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic struct platform_driver cci_platform_driver = { 1092b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .driver = { 1093b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .name = DRIVER_NAME, 1094b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .of_match_table = arm_cci_matches, 1095b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal }, 1096b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal .probe = cci_platform_probe, 1097b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal}; 1098b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1099b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int __init cci_platform_init(void) 1100b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 1101b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal int ret; 1102b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1103b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal ret = platform_driver_register(&cci_pmu_driver); 1104b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal if (ret) 1105b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return ret; 1106b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1107b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return platform_driver_register(&cci_platform_driver); 1108b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 1109b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1110b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#else 1111b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1112b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalstatic int __init cci_platform_init(void) 1113b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal{ 1114b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal return 0; 1115b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal} 1116b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal 1117b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawal#endif 1118ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi/* 1119ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * To sort out early init calls ordering a helper function is provided to 1120ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * check if the CCI driver has beed initialized. Function check if the driver 1121ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * has been initialized, if not it calls the init function that probes 1122ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi * the driver and updates the return value. 1123ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi */ 1124b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalbool cci_probed(void) 1125ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi{ 1126ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi return cci_init() == 0; 1127ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi} 1128ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiEXPORT_SYMBOL_GPL(cci_probed); 1129ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisi 1130ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo Pieralisiearly_initcall(cci_init); 1131b91c8f284acc2cb2aa43a1ce58322573ad983a14Punit Agrawalcore_initcall(cci_platform_init); 1132ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiMODULE_LICENSE("GPL"); 1133ed69bdd8fd9b2db68b915ce5f60fc51d4744a9b1Lorenzo PieralisiMODULE_DESCRIPTION("ARM CCI support"); 1134