aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorSuzuki K. Poulose <suzuki.poulose@arm.com>2015-03-18 08:24:39 -0400
committerWill Deacon <will.deacon@arm.com>2015-03-27 09:44:24 -0400
commitfc17c839448e498393009e06ca30a204eefaccee (patch)
tree9e83c56f317e2ad5bfde9341c3711df57665f95b /drivers/bus
parentf6b9e83ce05e362f4190cf2b4281d85cd094e541 (diff)
arm-cci: Abstract the CCI400 PMU specific definitions
CCI400 has different event specifications for PMU, for revsion 0 and revision 1. As of now, we check the revision every single time before using the parameters for the PMU. This patch abstracts the details of the pmu models in a struct (cci_pmu_model) and stores the information in cci_pmu at initialisation time, avoiding multiple probe operations. Tested-by: Sudeep Holla <sudeep.holla@arm.com> Acked-by: Punit Agrawal <punit.agrawal@arm.com> Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/arm-cci.c141
1 files changed, 81 insertions, 60 deletions
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 5d29ec34078e..ae3864d95e6c 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -79,19 +79,38 @@ static const struct of_device_id arm_cci_matches[] = {
79 79
80#define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */ 80#define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */
81 81
82/* Types of interfaces that can generate events */
83enum {
84 CCI_IF_SLAVE,
85 CCI_IF_MASTER,
86 CCI_IF_MAX,
87};
88
89struct event_range {
90 u32 min;
91 u32 max;
92};
93
82struct cci_pmu_hw_events { 94struct cci_pmu_hw_events {
83 struct perf_event *events[CCI_PMU_MAX_HW_EVENTS]; 95 struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
84 unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)]; 96 unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
85 raw_spinlock_t pmu_lock; 97 raw_spinlock_t pmu_lock;
86}; 98};
87 99
100struct cci_pmu_model {
101 char *name;
102 struct event_range event_ranges[CCI_IF_MAX];
103};
104
105static struct cci_pmu_model cci_pmu_models[];
106
88struct cci_pmu { 107struct cci_pmu {
89 void __iomem *base; 108 void __iomem *base;
90 struct pmu pmu; 109 struct pmu pmu;
91 int nr_irqs; 110 int nr_irqs;
92 int irqs[CCI_PMU_MAX_HW_EVENTS]; 111 int irqs[CCI_PMU_MAX_HW_EVENTS];
93 unsigned long active_irqs; 112 unsigned long active_irqs;
94 struct pmu_port_event_ranges *port_ranges; 113 const struct cci_pmu_model *model;
95 struct cci_pmu_hw_events hw_events; 114 struct cci_pmu_hw_events hw_events;
96 struct platform_device *plat_device; 115 struct platform_device *plat_device;
97 int num_events; 116 int num_events;
@@ -152,53 +171,11 @@ enum cci400_perf_events {
152#define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00 171#define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00
153#define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11 172#define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11
154 173
155struct pmu_port_event_ranges {
156 u8 slave_min;
157 u8 slave_max;
158 u8 master_min;
159 u8 master_max;
160};
161
162static struct pmu_port_event_ranges port_event_range[] = {
163 [CCI_REV_R0] = {
164 .slave_min = CCI_REV_R0_SLAVE_PORT_MIN_EV,
165 .slave_max = CCI_REV_R0_SLAVE_PORT_MAX_EV,
166 .master_min = CCI_REV_R0_MASTER_PORT_MIN_EV,
167 .master_max = CCI_REV_R0_MASTER_PORT_MAX_EV,
168 },
169 [CCI_REV_R1] = {
170 .slave_min = CCI_REV_R1_SLAVE_PORT_MIN_EV,
171 .slave_max = CCI_REV_R1_SLAVE_PORT_MAX_EV,
172 .master_min = CCI_REV_R1_MASTER_PORT_MIN_EV,
173 .master_max = CCI_REV_R1_MASTER_PORT_MAX_EV,
174 },
175};
176
177/*
178 * Export different PMU names for the different revisions so userspace knows
179 * because the event ids are different
180 */
181static char *const pmu_names[] = {
182 [CCI_REV_R0] = "CCI_400",
183 [CCI_REV_R1] = "CCI_400_r1",
184};
185
186static int pmu_is_valid_slave_event(u8 ev_code)
187{
188 return pmu->port_ranges->slave_min <= ev_code &&
189 ev_code <= pmu->port_ranges->slave_max;
190}
191
192static int pmu_is_valid_master_event(u8 ev_code)
193{
194 return pmu->port_ranges->master_min <= ev_code &&
195 ev_code <= pmu->port_ranges->master_max;
196}
197
198static int pmu_validate_hw_event(u8 hw_event) 174static int pmu_validate_hw_event(u8 hw_event)
199{ 175{
200 u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event); 176 u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
201 u8 ev_code = CCI_PMU_EVENT_CODE(hw_event); 177 u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
178 int if_type;
202 179
203 switch (ev_source) { 180 switch (ev_source) {
204 case CCI_PORT_S0: 181 case CCI_PORT_S0:
@@ -207,18 +184,22 @@ static int pmu_validate_hw_event(u8 hw_event)
207 case CCI_PORT_S3: 184 case CCI_PORT_S3:
208 case CCI_PORT_S4: 185 case CCI_PORT_S4:
209 /* Slave Interface */ 186 /* Slave Interface */
210 if (pmu_is_valid_slave_event(ev_code)) 187 if_type = CCI_IF_SLAVE;
211 return hw_event;
212 break; 188 break;
213 case CCI_PORT_M0: 189 case CCI_PORT_M0:
214 case CCI_PORT_M1: 190 case CCI_PORT_M1:
215 case CCI_PORT_M2: 191 case CCI_PORT_M2:
216 /* Master Interface */ 192 /* Master Interface */
217 if (pmu_is_valid_master_event(ev_code)) 193 if_type = CCI_IF_MASTER;
218 return hw_event;
219 break; 194 break;
195 default:
196 return -ENOENT;
220 } 197 }
221 198
199 if (ev_code >= pmu->model->event_ranges[if_type].min &&
200 ev_code <= pmu->model->event_ranges[if_type].max)
201 return hw_event;
202
222 return -ENOENT; 203 return -ENOENT;
223} 204}
224 205
@@ -234,11 +215,9 @@ static int probe_cci_revision(void)
234 return CCI_REV_R1; 215 return CCI_REV_R1;
235} 216}
236 217
237static struct pmu_port_event_ranges *port_range_by_rev(void) 218static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
238{ 219{
239 int rev = probe_cci_revision(); 220 return &cci_pmu_models[probe_cci_revision()];
240
241 return &port_event_range[rev];
242} 221}
243 222
244static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) 223static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
@@ -816,9 +795,9 @@ static const struct attribute_group *pmu_attr_groups[] = {
816 795
817static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev) 796static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
818{ 797{
819 char *name = pmu_names[probe_cci_revision()]; 798 char *name = cci_pmu->model->name;
820 cci_pmu->pmu = (struct pmu) { 799 cci_pmu->pmu = (struct pmu) {
821 .name = pmu_names[probe_cci_revision()], 800 .name = cci_pmu->model->name,
822 .task_ctx_nr = perf_invalid_context, 801 .task_ctx_nr = perf_invalid_context,
823 .pmu_enable = cci_pmu_enable, 802 .pmu_enable = cci_pmu_enable,
824 .pmu_disable = cci_pmu_disable, 803 .pmu_disable = cci_pmu_disable,
@@ -871,6 +850,35 @@ static struct notifier_block cci_pmu_cpu_nb = {
871 .priority = CPU_PRI_PERF + 1, 850 .priority = CPU_PRI_PERF + 1,
872}; 851};
873 852
853static struct cci_pmu_model cci_pmu_models[] = {
854 [CCI_REV_R0] = {
855 .name = "CCI_400",
856 .event_ranges = {
857 [CCI_IF_SLAVE] = {
858 CCI_REV_R0_SLAVE_PORT_MIN_EV,
859 CCI_REV_R0_SLAVE_PORT_MAX_EV,
860 },
861 [CCI_IF_MASTER] = {
862 CCI_REV_R0_MASTER_PORT_MIN_EV,
863 CCI_REV_R0_MASTER_PORT_MAX_EV,
864 },
865 },
866 },
867 [CCI_REV_R1] = {
868 .name = "CCI_400_r1",
869 .event_ranges = {
870 [CCI_IF_SLAVE] = {
871 CCI_REV_R1_SLAVE_PORT_MIN_EV,
872 CCI_REV_R1_SLAVE_PORT_MAX_EV,
873 },
874 [CCI_IF_MASTER] = {
875 CCI_REV_R1_MASTER_PORT_MIN_EV,
876 CCI_REV_R1_MASTER_PORT_MAX_EV,
877 },
878 },
879 },
880};
881
874static const struct of_device_id arm_cci_pmu_matches[] = { 882static const struct of_device_id arm_cci_pmu_matches[] = {
875 { 883 {
876 .compatible = "arm,cci-400-pmu", 884 .compatible = "arm,cci-400-pmu",
@@ -878,6 +886,16 @@ static const struct of_device_id arm_cci_pmu_matches[] = {
878 {}, 886 {},
879}; 887};
880 888
889static inline const struct cci_pmu_model *get_cci_model(struct platform_device *pdev)
890{
891 const struct of_device_id *match = of_match_node(arm_cci_pmu_matches,
892 pdev->dev.of_node);
893 if (!match)
894 return NULL;
895
896 return probe_cci_model(pdev);
897}
898
881static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) 899static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
882{ 900{
883 int i; 901 int i;
@@ -893,11 +911,19 @@ static int cci_pmu_probe(struct platform_device *pdev)
893{ 911{
894 struct resource *res; 912 struct resource *res;
895 int i, ret, irq; 913 int i, ret, irq;
914 const struct cci_pmu_model *model;
915
916 model = get_cci_model(pdev);
917 if (!model) {
918 dev_warn(&pdev->dev, "CCI PMU version not supported\n");
919 return -ENODEV;
920 }
896 921
897 pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); 922 pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
898 if (!pmu) 923 if (!pmu)
899 return -ENOMEM; 924 return -ENOMEM;
900 925
926 pmu->model = model;
901 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 927 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
902 pmu->base = devm_ioremap_resource(&pdev->dev, res); 928 pmu->base = devm_ioremap_resource(&pdev->dev, res);
903 if (IS_ERR(pmu->base)) 929 if (IS_ERR(pmu->base))
@@ -929,12 +955,6 @@ static int cci_pmu_probe(struct platform_device *pdev)
929 return -EINVAL; 955 return -EINVAL;
930 } 956 }
931 957
932 pmu->port_ranges = port_range_by_rev();
933 if (!pmu->port_ranges) {
934 dev_warn(&pdev->dev, "CCI PMU version not supported\n");
935 return -EINVAL;
936 }
937
938 raw_spin_lock_init(&pmu->hw_events.pmu_lock); 958 raw_spin_lock_init(&pmu->hw_events.pmu_lock);
939 mutex_init(&pmu->reserve_mutex); 959 mutex_init(&pmu->reserve_mutex);
940 atomic_set(&pmu->active_events, 0); 960 atomic_set(&pmu->active_events, 0);
@@ -948,6 +968,7 @@ static int cci_pmu_probe(struct platform_device *pdev)
948 if (ret) 968 if (ret)
949 return ret; 969 return ret;
950 970
971 pr_info("ARM %s PMU driver probed", pmu->model->name);
951 return 0; 972 return 0;
952} 973}
953 974