Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Suzuki K. Poulose and committed by
Will Deacon
fc17c839 f6b9e83c

+81 -60
+81 -60
drivers/bus/arm-cci.c
··· 79 79 80 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 */ 83 + enum { 84 + CCI_IF_SLAVE, 85 + CCI_IF_MASTER, 86 + CCI_IF_MAX, 87 + }; 88 + 89 + struct event_range { 90 + u32 min; 91 + u32 max; 92 + }; 93 + 82 94 struct cci_pmu_hw_events { 83 95 struct perf_event *events[CCI_PMU_MAX_HW_EVENTS]; 84 96 unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)]; 85 97 raw_spinlock_t pmu_lock; 86 98 }; 99 + 100 + struct cci_pmu_model { 101 + char *name; 102 + struct event_range event_ranges[CCI_IF_MAX]; 103 + }; 104 + 105 + static struct cci_pmu_model cci_pmu_models[]; 87 106 88 107 struct cci_pmu { 89 108 void __iomem *base; ··· 110 91 int nr_irqs; 111 92 int irqs[CCI_PMU_MAX_HW_EVENTS]; 112 93 unsigned long active_irqs; 113 - struct pmu_port_event_ranges *port_ranges; 94 + const struct cci_pmu_model *model; 114 95 struct cci_pmu_hw_events hw_events; 115 96 struct platform_device *plat_device; 116 97 int num_events; ··· 171 152 #define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00 172 153 #define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11 173 154 174 - struct pmu_port_event_ranges { 175 - u8 slave_min; 176 - u8 slave_max; 177 - u8 master_min; 178 - u8 master_max; 179 - }; 180 - 181 - static struct pmu_port_event_ranges port_event_range[] = { 182 - [CCI_REV_R0] = { 183 - .slave_min = CCI_REV_R0_SLAVE_PORT_MIN_EV, 184 - .slave_max = CCI_REV_R0_SLAVE_PORT_MAX_EV, 185 - .master_min = CCI_REV_R0_MASTER_PORT_MIN_EV, 186 - .master_max = CCI_REV_R0_MASTER_PORT_MAX_EV, 187 - }, 188 - [CCI_REV_R1] = { 189 - .slave_min = CCI_REV_R1_SLAVE_PORT_MIN_EV, 190 - .slave_max = CCI_REV_R1_SLAVE_PORT_MAX_EV, 191 - .master_min = CCI_REV_R1_MASTER_PORT_MIN_EV, 192 - .master_max = CCI_REV_R1_MASTER_PORT_MAX_EV, 193 - }, 194 - }; 195 - 196 - /* 197 - * Export different PMU names for the different revisions so userspace knows 198 - * because the event ids are different 199 - */ 200 - static char *const pmu_names[] = { 201 - [CCI_REV_R0] = "CCI_400", 202 - [CCI_REV_R1] = "CCI_400_r1", 203 - }; 204 - 205 - static int pmu_is_valid_slave_event(u8 ev_code) 206 - { 207 - return pmu->port_ranges->slave_min <= ev_code && 208 - ev_code <= pmu->port_ranges->slave_max; 209 - } 210 - 211 - static int pmu_is_valid_master_event(u8 ev_code) 212 - { 213 - return pmu->port_ranges->master_min <= ev_code && 214 - ev_code <= pmu->port_ranges->master_max; 215 - } 216 - 217 155 static int pmu_validate_hw_event(u8 hw_event) 218 156 { 219 157 u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event); 220 158 u8 ev_code = CCI_PMU_EVENT_CODE(hw_event); 159 + int if_type; 221 160 222 161 switch (ev_source) { 223 162 case CCI_PORT_S0: ··· 184 207 case CCI_PORT_S3: 185 208 case CCI_PORT_S4: 186 209 /* Slave Interface */ 187 - if (pmu_is_valid_slave_event(ev_code)) 188 - return hw_event; 210 + if_type = CCI_IF_SLAVE; 189 211 break; 190 212 case CCI_PORT_M0: 191 213 case CCI_PORT_M1: 192 214 case CCI_PORT_M2: 193 215 /* Master Interface */ 194 - if (pmu_is_valid_master_event(ev_code)) 195 - return hw_event; 216 + if_type = CCI_IF_MASTER; 196 217 break; 218 + default: 219 + return -ENOENT; 197 220 } 221 + 222 + if (ev_code >= pmu->model->event_ranges[if_type].min && 223 + ev_code <= pmu->model->event_ranges[if_type].max) 224 + return hw_event; 198 225 199 226 return -ENOENT; 200 227 } ··· 215 234 return CCI_REV_R1; 216 235 } 217 236 218 - static struct pmu_port_event_ranges *port_range_by_rev(void) 237 + static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev) 219 238 { 220 - int rev = probe_cci_revision(); 221 - 222 - return &port_event_range[rev]; 239 + return &cci_pmu_models[probe_cci_revision()]; 223 240 } 224 241 225 242 static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) ··· 795 816 796 817 static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev) 797 818 { 798 - char *name = pmu_names[probe_cci_revision()]; 819 + char *name = cci_pmu->model->name; 799 820 cci_pmu->pmu = (struct pmu) { 800 - .name = pmu_names[probe_cci_revision()], 821 + .name = cci_pmu->model->name, 801 822 .task_ctx_nr = perf_invalid_context, 802 823 .pmu_enable = cci_pmu_enable, 803 824 .pmu_disable = cci_pmu_disable, ··· 850 871 .priority = CPU_PRI_PERF + 1, 851 872 }; 852 873 874 + static struct cci_pmu_model cci_pmu_models[] = { 875 + [CCI_REV_R0] = { 876 + .name = "CCI_400", 877 + .event_ranges = { 878 + [CCI_IF_SLAVE] = { 879 + CCI_REV_R0_SLAVE_PORT_MIN_EV, 880 + CCI_REV_R0_SLAVE_PORT_MAX_EV, 881 + }, 882 + [CCI_IF_MASTER] = { 883 + CCI_REV_R0_MASTER_PORT_MIN_EV, 884 + CCI_REV_R0_MASTER_PORT_MAX_EV, 885 + }, 886 + }, 887 + }, 888 + [CCI_REV_R1] = { 889 + .name = "CCI_400_r1", 890 + .event_ranges = { 891 + [CCI_IF_SLAVE] = { 892 + CCI_REV_R1_SLAVE_PORT_MIN_EV, 893 + CCI_REV_R1_SLAVE_PORT_MAX_EV, 894 + }, 895 + [CCI_IF_MASTER] = { 896 + CCI_REV_R1_MASTER_PORT_MIN_EV, 897 + CCI_REV_R1_MASTER_PORT_MAX_EV, 898 + }, 899 + }, 900 + }, 901 + }; 902 + 853 903 static const struct of_device_id arm_cci_pmu_matches[] = { 854 904 { 855 905 .compatible = "arm,cci-400-pmu", 856 906 }, 857 907 {}, 858 908 }; 909 + 910 + static inline const struct cci_pmu_model *get_cci_model(struct platform_device *pdev) 911 + { 912 + const struct of_device_id *match = of_match_node(arm_cci_pmu_matches, 913 + pdev->dev.of_node); 914 + if (!match) 915 + return NULL; 916 + 917 + return probe_cci_model(pdev); 918 + } 859 919 860 920 static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) 861 921 { ··· 911 893 { 912 894 struct resource *res; 913 895 int i, ret, irq; 896 + const struct cci_pmu_model *model; 897 + 898 + model = get_cci_model(pdev); 899 + if (!model) { 900 + dev_warn(&pdev->dev, "CCI PMU version not supported\n"); 901 + return -ENODEV; 902 + } 914 903 915 904 pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); 916 905 if (!pmu) 917 906 return -ENOMEM; 918 907 908 + pmu->model = model; 919 909 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 920 910 pmu->base = devm_ioremap_resource(&pdev->dev, res); 921 911 if (IS_ERR(pmu->base)) ··· 955 929 return -EINVAL; 956 930 } 957 931 958 - pmu->port_ranges = port_range_by_rev(); 959 - if (!pmu->port_ranges) { 960 - dev_warn(&pdev->dev, "CCI PMU version not supported\n"); 961 - return -EINVAL; 962 - } 963 - 964 932 raw_spin_lock_init(&pmu->hw_events.pmu_lock); 965 933 mutex_init(&pmu->reserve_mutex); 966 934 atomic_set(&pmu->active_events, 0); ··· 968 948 if (ret) 969 949 return ret; 970 950 951 + pr_info("ARM %s PMU driver probed", pmu->model->name); 971 952 return 0; 972 953 } 973 954