1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HiSilicon SoC L3C uncore Hardware event counters support 4 * 5 * Copyright (C) 2017 Hisilicon Limited 6 * Author: Anurup M <anurup.m@huawei.com> 7 * Shaokun Zhang <zhangshaokun@hisilicon.com> 8 * 9 * This code is based on the uncore PMUs like arm-cci and arm-ccn. 10 */ 11 #include <linux/acpi.h> 12 #include <linux/bug.h> 13 #include <linux/cpuhotplug.h> 14 #include <linux/interrupt.h> 15 #include <linux/irq.h> 16 #include <linux/list.h> 17 #include <linux/platform_device.h> 18 #include <linux/smp.h> 19 20 #include "hisi_uncore_pmu.h" 21 22 /* L3C register definition */ 23 #define L3C_PERF_CTRL 0x0408 24 #define L3C_INT_MASK 0x0800 25 #define L3C_INT_STATUS 0x0808 26 #define L3C_INT_CLEAR 0x080c 27 #define L3C_EVENT_CTRL 0x1c00 28 #define L3C_VERSION 0x1cf0 29 #define L3C_EVENT_TYPE0 0x1d00 30 /* 31 * Each counter is 48-bits and [48:63] are reserved 32 * which are Read-As-Zero and Writes-Ignored. 33 */ 34 #define L3C_CNTR0_LOWER 0x1e00 35 36 /* L3C has 8-counters */ 37 #define L3C_NR_COUNTERS 0x8 38 39 #define L3C_PERF_CTRL_EN 0x10000 40 #define L3C_EVTYPE_NONE 0xff 41 42 /* 43 * Select the counter register offset using the counter index 44 */ 45 static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx) 46 { 47 return (L3C_CNTR0_LOWER + (cntr_idx * 8)); 48 } 49 50 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu, 51 struct hw_perf_event *hwc) 52 { 53 u32 idx = hwc->idx; 54 55 if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) { 56 dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx); 57 return 0; 58 } 59 60 /* Read 64-bits and the upper 16 bits are RAZ */ 61 return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx)); 62 } 63 64 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu, 65 struct hw_perf_event *hwc, u64 val) 66 { 67 u32 idx = hwc->idx; 68 69 if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) { 70 dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx); 71 return; 72 } 73 74 /* Write 64-bits and the upper 16 bits are WI */ 75 writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx)); 76 } 77 78 static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx, 79 u32 type) 80 { 81 u32 reg, reg_idx, shift, val; 82 83 /* 84 * Select the appropriate event select register(L3C_EVENT_TYPE0/1). 85 * There are 2 event select registers for the 8 hardware counters. 86 * Event code is 8-bits and for the former 4 hardware counters, 87 * L3C_EVENT_TYPE0 is chosen. For the latter 4 hardware counters, 88 * L3C_EVENT_TYPE1 is chosen. 89 */ 90 reg = L3C_EVENT_TYPE0 + (idx / 4) * 4; 91 reg_idx = idx % 4; 92 shift = 8 * reg_idx; 93 94 /* Write event code to L3C_EVENT_TYPEx Register */ 95 val = readl(l3c_pmu->base + reg); 96 val &= ~(L3C_EVTYPE_NONE << shift); 97 val |= (type << shift); 98 writel(val, l3c_pmu->base + reg); 99 } 100 101 static void hisi_l3c_pmu_start_counters(struct hisi_pmu *l3c_pmu) 102 { 103 u32 val; 104 105 /* 106 * Set perf_enable bit in L3C_PERF_CTRL register to start counting 107 * for all enabled counters. 108 */ 109 val = readl(l3c_pmu->base + L3C_PERF_CTRL); 110 val |= L3C_PERF_CTRL_EN; 111 writel(val, l3c_pmu->base + L3C_PERF_CTRL); 112 } 113 114 static void hisi_l3c_pmu_stop_counters(struct hisi_pmu *l3c_pmu) 115 { 116 u32 val; 117 118 /* 119 * Clear perf_enable bit in L3C_PERF_CTRL register to stop counting 120 * for all enabled counters. 121 */ 122 val = readl(l3c_pmu->base + L3C_PERF_CTRL); 123 val &= ~(L3C_PERF_CTRL_EN); 124 writel(val, l3c_pmu->base + L3C_PERF_CTRL); 125 } 126 127 static void hisi_l3c_pmu_enable_counter(struct hisi_pmu *l3c_pmu, 128 struct hw_perf_event *hwc) 129 { 130 u32 val; 131 132 /* Enable counter index in L3C_EVENT_CTRL register */ 133 val = readl(l3c_pmu->base + L3C_EVENT_CTRL); 134 val |= (1 << hwc->idx); 135 writel(val, l3c_pmu->base + L3C_EVENT_CTRL); 136 } 137 138 static void hisi_l3c_pmu_disable_counter(struct hisi_pmu *l3c_pmu, 139 struct hw_perf_event *hwc) 140 { 141 u32 val; 142 143 /* Clear counter index in L3C_EVENT_CTRL register */ 144 val = readl(l3c_pmu->base + L3C_EVENT_CTRL); 145 val &= ~(1 << hwc->idx); 146 writel(val, l3c_pmu->base + L3C_EVENT_CTRL); 147 } 148 149 static void hisi_l3c_pmu_enable_counter_int(struct hisi_pmu *l3c_pmu, 150 struct hw_perf_event *hwc) 151 { 152 u32 val; 153 154 val = readl(l3c_pmu->base + L3C_INT_MASK); 155 /* Write 0 to enable interrupt */ 156 val &= ~(1 << hwc->idx); 157 writel(val, l3c_pmu->base + L3C_INT_MASK); 158 } 159 160 static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu, 161 struct hw_perf_event *hwc) 162 { 163 u32 val; 164 165 val = readl(l3c_pmu->base + L3C_INT_MASK); 166 /* Write 1 to mask interrupt */ 167 val |= (1 << hwc->idx); 168 writel(val, l3c_pmu->base + L3C_INT_MASK); 169 } 170 171 static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id) 172 { 173 struct hisi_pmu *l3c_pmu = dev_id; 174 struct perf_event *event; 175 unsigned long overflown; 176 int idx; 177 178 /* Read L3C_INT_STATUS register */ 179 overflown = readl(l3c_pmu->base + L3C_INT_STATUS); 180 if (!overflown) 181 return IRQ_NONE; 182 183 /* 184 * Find the counter index which overflowed if the bit was set 185 * and handle it. 186 */ 187 for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) { 188 /* Write 1 to clear the IRQ status flag */ 189 writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR); 190 191 /* Get the corresponding event struct */ 192 event = l3c_pmu->pmu_events.hw_events[idx]; 193 if (!event) 194 continue; 195 196 hisi_uncore_pmu_event_update(event); 197 hisi_uncore_pmu_set_event_period(event); 198 } 199 200 return IRQ_HANDLED; 201 } 202 203 static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu, 204 struct platform_device *pdev) 205 { 206 int irq, ret; 207 208 /* Read and init IRQ */ 209 irq = platform_get_irq(pdev, 0); 210 if (irq < 0) 211 return irq; 212 213 ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr, 214 IRQF_NOBALANCING | IRQF_NO_THREAD, 215 dev_name(&pdev->dev), l3c_pmu); 216 if (ret < 0) { 217 dev_err(&pdev->dev, 218 "Fail to request IRQ:%d ret:%d\n", irq, ret); 219 return ret; 220 } 221 222 l3c_pmu->irq = irq; 223 224 return 0; 225 } 226 227 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = { 228 { "HISI0213", }, 229 {}, 230 }; 231 MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match); 232 233 static int hisi_l3c_pmu_init_data(struct platform_device *pdev, 234 struct hisi_pmu *l3c_pmu) 235 { 236 unsigned long long id; 237 acpi_status status; 238 239 status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), 240 "_UID", NULL, &id); 241 if (ACPI_FAILURE(status)) 242 return -EINVAL; 243 244 l3c_pmu->index_id = id; 245 246 /* 247 * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while 248 * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1]. 249 */ 250 if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", 251 &l3c_pmu->sccl_id)) { 252 dev_err(&pdev->dev, "Can not read l3c sccl-id!\n"); 253 return -EINVAL; 254 } 255 256 if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id", 257 &l3c_pmu->ccl_id)) { 258 dev_err(&pdev->dev, "Can not read l3c ccl-id!\n"); 259 return -EINVAL; 260 } 261 262 l3c_pmu->base = devm_platform_ioremap_resource(pdev, 0); 263 if (IS_ERR(l3c_pmu->base)) { 264 dev_err(&pdev->dev, "ioremap failed for l3c_pmu resource\n"); 265 return PTR_ERR(l3c_pmu->base); 266 } 267 268 l3c_pmu->identifier = readl(l3c_pmu->base + L3C_VERSION); 269 270 return 0; 271 } 272 273 static struct attribute *hisi_l3c_pmu_format_attr[] = { 274 HISI_PMU_FORMAT_ATTR(event, "config:0-7"), 275 NULL, 276 }; 277 278 static const struct attribute_group hisi_l3c_pmu_format_group = { 279 .name = "format", 280 .attrs = hisi_l3c_pmu_format_attr, 281 }; 282 283 static struct attribute *hisi_l3c_pmu_events_attr[] = { 284 HISI_PMU_EVENT_ATTR(rd_cpipe, 0x00), 285 HISI_PMU_EVENT_ATTR(wr_cpipe, 0x01), 286 HISI_PMU_EVENT_ATTR(rd_hit_cpipe, 0x02), 287 HISI_PMU_EVENT_ATTR(wr_hit_cpipe, 0x03), 288 HISI_PMU_EVENT_ATTR(victim_num, 0x04), 289 HISI_PMU_EVENT_ATTR(rd_spipe, 0x20), 290 HISI_PMU_EVENT_ATTR(wr_spipe, 0x21), 291 HISI_PMU_EVENT_ATTR(rd_hit_spipe, 0x22), 292 HISI_PMU_EVENT_ATTR(wr_hit_spipe, 0x23), 293 HISI_PMU_EVENT_ATTR(back_invalid, 0x29), 294 HISI_PMU_EVENT_ATTR(retry_cpu, 0x40), 295 HISI_PMU_EVENT_ATTR(retry_ring, 0x41), 296 HISI_PMU_EVENT_ATTR(prefetch_drop, 0x42), 297 NULL, 298 }; 299 300 static const struct attribute_group hisi_l3c_pmu_events_group = { 301 .name = "events", 302 .attrs = hisi_l3c_pmu_events_attr, 303 }; 304 305 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); 306 307 static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = { 308 &dev_attr_cpumask.attr, 309 NULL, 310 }; 311 312 static const struct attribute_group hisi_l3c_pmu_cpumask_attr_group = { 313 .attrs = hisi_l3c_pmu_cpumask_attrs, 314 }; 315 316 static struct device_attribute hisi_l3c_pmu_identifier_attr = 317 __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL); 318 319 static struct attribute *hisi_l3c_pmu_identifier_attrs[] = { 320 &hisi_l3c_pmu_identifier_attr.attr, 321 NULL 322 }; 323 324 static struct attribute_group hisi_l3c_pmu_identifier_group = { 325 .attrs = hisi_l3c_pmu_identifier_attrs, 326 }; 327 328 static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = { 329 &hisi_l3c_pmu_format_group, 330 &hisi_l3c_pmu_events_group, 331 &hisi_l3c_pmu_cpumask_attr_group, 332 &hisi_l3c_pmu_identifier_group, 333 NULL, 334 }; 335 336 static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { 337 .write_evtype = hisi_l3c_pmu_write_evtype, 338 .get_event_idx = hisi_uncore_pmu_get_event_idx, 339 .start_counters = hisi_l3c_pmu_start_counters, 340 .stop_counters = hisi_l3c_pmu_stop_counters, 341 .enable_counter = hisi_l3c_pmu_enable_counter, 342 .disable_counter = hisi_l3c_pmu_disable_counter, 343 .enable_counter_int = hisi_l3c_pmu_enable_counter_int, 344 .disable_counter_int = hisi_l3c_pmu_disable_counter_int, 345 .write_counter = hisi_l3c_pmu_write_counter, 346 .read_counter = hisi_l3c_pmu_read_counter, 347 }; 348 349 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev, 350 struct hisi_pmu *l3c_pmu) 351 { 352 int ret; 353 354 ret = hisi_l3c_pmu_init_data(pdev, l3c_pmu); 355 if (ret) 356 return ret; 357 358 ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev); 359 if (ret) 360 return ret; 361 362 l3c_pmu->num_counters = L3C_NR_COUNTERS; 363 l3c_pmu->counter_bits = 48; 364 l3c_pmu->ops = &hisi_uncore_l3c_ops; 365 l3c_pmu->dev = &pdev->dev; 366 l3c_pmu->on_cpu = -1; 367 l3c_pmu->check_event = 0x59; 368 369 return 0; 370 } 371 372 static int hisi_l3c_pmu_probe(struct platform_device *pdev) 373 { 374 struct hisi_pmu *l3c_pmu; 375 char *name; 376 int ret; 377 378 l3c_pmu = devm_kzalloc(&pdev->dev, sizeof(*l3c_pmu), GFP_KERNEL); 379 if (!l3c_pmu) 380 return -ENOMEM; 381 382 platform_set_drvdata(pdev, l3c_pmu); 383 384 ret = hisi_l3c_pmu_dev_probe(pdev, l3c_pmu); 385 if (ret) 386 return ret; 387 388 ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, 389 &l3c_pmu->node); 390 if (ret) { 391 dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); 392 return ret; 393 } 394 395 name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u", 396 l3c_pmu->sccl_id, l3c_pmu->index_id); 397 l3c_pmu->pmu = (struct pmu) { 398 .name = name, 399 .module = THIS_MODULE, 400 .task_ctx_nr = perf_invalid_context, 401 .event_init = hisi_uncore_pmu_event_init, 402 .pmu_enable = hisi_uncore_pmu_enable, 403 .pmu_disable = hisi_uncore_pmu_disable, 404 .add = hisi_uncore_pmu_add, 405 .del = hisi_uncore_pmu_del, 406 .start = hisi_uncore_pmu_start, 407 .stop = hisi_uncore_pmu_stop, 408 .read = hisi_uncore_pmu_read, 409 .attr_groups = hisi_l3c_pmu_attr_groups, 410 .capabilities = PERF_PMU_CAP_NO_EXCLUDE, 411 }; 412 413 ret = perf_pmu_register(&l3c_pmu->pmu, name, -1); 414 if (ret) { 415 dev_err(l3c_pmu->dev, "L3C PMU register failed!\n"); 416 cpuhp_state_remove_instance_nocalls( 417 CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node); 418 irq_set_affinity_hint(l3c_pmu->irq, NULL); 419 } 420 421 return ret; 422 } 423 424 static int hisi_l3c_pmu_remove(struct platform_device *pdev) 425 { 426 struct hisi_pmu *l3c_pmu = platform_get_drvdata(pdev); 427 428 perf_pmu_unregister(&l3c_pmu->pmu); 429 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, 430 &l3c_pmu->node); 431 irq_set_affinity_hint(l3c_pmu->irq, NULL); 432 433 return 0; 434 } 435 436 static struct platform_driver hisi_l3c_pmu_driver = { 437 .driver = { 438 .name = "hisi_l3c_pmu", 439 .acpi_match_table = ACPI_PTR(hisi_l3c_pmu_acpi_match), 440 .suppress_bind_attrs = true, 441 }, 442 .probe = hisi_l3c_pmu_probe, 443 .remove = hisi_l3c_pmu_remove, 444 }; 445 446 static int __init hisi_l3c_pmu_module_init(void) 447 { 448 int ret; 449 450 ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, 451 "AP_PERF_ARM_HISI_L3_ONLINE", 452 hisi_uncore_pmu_online_cpu, 453 hisi_uncore_pmu_offline_cpu); 454 if (ret) { 455 pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret); 456 return ret; 457 } 458 459 ret = platform_driver_register(&hisi_l3c_pmu_driver); 460 if (ret) 461 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE); 462 463 return ret; 464 } 465 module_init(hisi_l3c_pmu_module_init); 466 467 static void __exit hisi_l3c_pmu_module_exit(void) 468 { 469 platform_driver_unregister(&hisi_l3c_pmu_driver); 470 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE); 471 } 472 module_exit(hisi_l3c_pmu_module_exit); 473 474 MODULE_DESCRIPTION("HiSilicon SoC L3C uncore PMU driver"); 475 MODULE_LICENSE("GPL v2"); 476 MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>"); 477 MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>"); 478