1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HiSilicon SoC HHA uncore Hardware event counters support 4 * 5 * Copyright (C) 2017 Hisilicon Limited 6 * Author: Shaokun Zhang <zhangshaokun@hisilicon.com> 7 * Anurup M <anurup.m@huawei.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 /* HHA register definition */ 23 #define HHA_INT_MASK 0x0804 24 #define HHA_INT_STATUS 0x0808 25 #define HHA_INT_CLEAR 0x080C 26 #define HHA_PERF_CTRL 0x1E00 27 #define HHA_EVENT_CTRL 0x1E04 28 #define HHA_EVENT_TYPE0 0x1E80 29 /* 30 * Each counter is 48-bits and [48:63] are reserved 31 * which are Read-As-Zero and Writes-Ignored. 32 */ 33 #define HHA_CNT0_LOWER 0x1F00 34 35 /* HHA has 16-counters */ 36 #define HHA_NR_COUNTERS 0x10 37 38 #define HHA_PERF_CTRL_EN 0x1 39 #define HHA_EVTYPE_NONE 0xff 40 41 /* 42 * Select the counter register offset using the counter index 43 * each counter is 48-bits. 44 */ 45 static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx) 46 { 47 return (HHA_CNT0_LOWER + (cntr_idx * 8)); 48 } 49 50 static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu, 51 struct hw_perf_event *hwc) 52 { 53 u32 idx = hwc->idx; 54 55 if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) { 56 dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx); 57 return 0; 58 } 59 60 /* Read 64 bits and like L3C, top 16 bits are RAZ */ 61 return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx)); 62 } 63 64 static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu, 65 struct hw_perf_event *hwc, u64 val) 66 { 67 u32 idx = hwc->idx; 68 69 if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) { 70 dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx); 71 return; 72 } 73 74 /* Write 64 bits and like L3C, top 16 bits are WI */ 75 writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx)); 76 } 77 78 static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx, 79 u32 type) 80 { 81 u32 reg, reg_idx, shift, val; 82 83 /* 84 * Select the appropriate event select register(HHA_EVENT_TYPEx). 85 * There are 4 event select registers for the 16 hardware counters. 86 * Event code is 8-bits and for the first 4 hardware counters, 87 * HHA_EVENT_TYPE0 is chosen. For the next 4 hardware counters, 88 * HHA_EVENT_TYPE1 is chosen and so on. 89 */ 90 reg = HHA_EVENT_TYPE0 + 4 * (idx / 4); 91 reg_idx = idx % 4; 92 shift = 8 * reg_idx; 93 94 /* Write event code to HHA_EVENT_TYPEx register */ 95 val = readl(hha_pmu->base + reg); 96 val &= ~(HHA_EVTYPE_NONE << shift); 97 val |= (type << shift); 98 writel(val, hha_pmu->base + reg); 99 } 100 101 static void hisi_hha_pmu_start_counters(struct hisi_pmu *hha_pmu) 102 { 103 u32 val; 104 105 /* 106 * Set perf_enable bit in HHA_PERF_CTRL to start event 107 * counting for all enabled counters. 108 */ 109 val = readl(hha_pmu->base + HHA_PERF_CTRL); 110 val |= HHA_PERF_CTRL_EN; 111 writel(val, hha_pmu->base + HHA_PERF_CTRL); 112 } 113 114 static void hisi_hha_pmu_stop_counters(struct hisi_pmu *hha_pmu) 115 { 116 u32 val; 117 118 /* 119 * Clear perf_enable bit in HHA_PERF_CTRL to stop event 120 * counting for all enabled counters. 121 */ 122 val = readl(hha_pmu->base + HHA_PERF_CTRL); 123 val &= ~(HHA_PERF_CTRL_EN); 124 writel(val, hha_pmu->base + HHA_PERF_CTRL); 125 } 126 127 static void hisi_hha_pmu_enable_counter(struct hisi_pmu *hha_pmu, 128 struct hw_perf_event *hwc) 129 { 130 u32 val; 131 132 /* Enable counter index in HHA_EVENT_CTRL register */ 133 val = readl(hha_pmu->base + HHA_EVENT_CTRL); 134 val |= (1 << hwc->idx); 135 writel(val, hha_pmu->base + HHA_EVENT_CTRL); 136 } 137 138 static void hisi_hha_pmu_disable_counter(struct hisi_pmu *hha_pmu, 139 struct hw_perf_event *hwc) 140 { 141 u32 val; 142 143 /* Clear counter index in HHA_EVENT_CTRL register */ 144 val = readl(hha_pmu->base + HHA_EVENT_CTRL); 145 val &= ~(1 << hwc->idx); 146 writel(val, hha_pmu->base + HHA_EVENT_CTRL); 147 } 148 149 static void hisi_hha_pmu_enable_counter_int(struct hisi_pmu *hha_pmu, 150 struct hw_perf_event *hwc) 151 { 152 u32 val; 153 154 /* Write 0 to enable interrupt */ 155 val = readl(hha_pmu->base + HHA_INT_MASK); 156 val &= ~(1 << hwc->idx); 157 writel(val, hha_pmu->base + HHA_INT_MASK); 158 } 159 160 static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu, 161 struct hw_perf_event *hwc) 162 { 163 u32 val; 164 165 /* Write 1 to mask interrupt */ 166 val = readl(hha_pmu->base + HHA_INT_MASK); 167 val |= (1 << hwc->idx); 168 writel(val, hha_pmu->base + HHA_INT_MASK); 169 } 170 171 static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id) 172 { 173 struct hisi_pmu *hha_pmu = dev_id; 174 struct perf_event *event; 175 unsigned long overflown; 176 int idx; 177 178 /* Read HHA_INT_STATUS register */ 179 overflown = readl(hha_pmu->base + HHA_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, HHA_NR_COUNTERS) { 188 /* Write 1 to clear the IRQ status flag */ 189 writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR); 190 191 /* Get the corresponding event struct */ 192 event = hha_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_hha_pmu_init_irq(struct hisi_pmu *hha_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_hha_pmu_isr, 214 IRQF_NOBALANCING | IRQF_NO_THREAD, 215 dev_name(&pdev->dev), hha_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 hha_pmu->irq = irq; 223 224 return 0; 225 } 226 227 static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = { 228 { "HISI0243", }, 229 {}, 230 }; 231 MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match); 232 233 static int hisi_hha_pmu_init_data(struct platform_device *pdev, 234 struct hisi_pmu *hha_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 hha_pmu->index_id = id; 245 246 /* 247 * Use SCCL_ID and UID to identify the HHA PMU, while 248 * SCCL_ID is in MPIDR[aff2]. 249 */ 250 if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", 251 &hha_pmu->sccl_id)) { 252 dev_err(&pdev->dev, "Can not read hha sccl-id!\n"); 253 return -EINVAL; 254 } 255 /* HHA PMUs only share the same SCCL */ 256 hha_pmu->ccl_id = -1; 257 258 hha_pmu->base = devm_platform_ioremap_resource(pdev, 0); 259 if (IS_ERR(hha_pmu->base)) { 260 dev_err(&pdev->dev, "ioremap failed for hha_pmu resource\n"); 261 return PTR_ERR(hha_pmu->base); 262 } 263 264 return 0; 265 } 266 267 static struct attribute *hisi_hha_pmu_format_attr[] = { 268 HISI_PMU_FORMAT_ATTR(event, "config:0-7"), 269 NULL, 270 }; 271 272 static const struct attribute_group hisi_hha_pmu_format_group = { 273 .name = "format", 274 .attrs = hisi_hha_pmu_format_attr, 275 }; 276 277 static struct attribute *hisi_hha_pmu_events_attr[] = { 278 HISI_PMU_EVENT_ATTR(rx_ops_num, 0x00), 279 HISI_PMU_EVENT_ATTR(rx_outer, 0x01), 280 HISI_PMU_EVENT_ATTR(rx_sccl, 0x02), 281 HISI_PMU_EVENT_ATTR(rx_ccix, 0x03), 282 HISI_PMU_EVENT_ATTR(rx_wbi, 0x04), 283 HISI_PMU_EVENT_ATTR(rx_wbip, 0x05), 284 HISI_PMU_EVENT_ATTR(rx_wtistash, 0x11), 285 HISI_PMU_EVENT_ATTR(rd_ddr_64b, 0x1c), 286 HISI_PMU_EVENT_ATTR(wr_ddr_64b, 0x1d), 287 HISI_PMU_EVENT_ATTR(rd_ddr_128b, 0x1e), 288 HISI_PMU_EVENT_ATTR(wr_ddr_128b, 0x1f), 289 HISI_PMU_EVENT_ATTR(spill_num, 0x20), 290 HISI_PMU_EVENT_ATTR(spill_success, 0x21), 291 HISI_PMU_EVENT_ATTR(bi_num, 0x23), 292 HISI_PMU_EVENT_ATTR(mediated_num, 0x32), 293 HISI_PMU_EVENT_ATTR(tx_snp_num, 0x33), 294 HISI_PMU_EVENT_ATTR(tx_snp_outer, 0x34), 295 HISI_PMU_EVENT_ATTR(tx_snp_ccix, 0x35), 296 HISI_PMU_EVENT_ATTR(rx_snprspdata, 0x38), 297 HISI_PMU_EVENT_ATTR(rx_snprsp_outer, 0x3c), 298 HISI_PMU_EVENT_ATTR(sdir-lookup, 0x40), 299 HISI_PMU_EVENT_ATTR(edir-lookup, 0x41), 300 HISI_PMU_EVENT_ATTR(sdir-hit, 0x42), 301 HISI_PMU_EVENT_ATTR(edir-hit, 0x43), 302 HISI_PMU_EVENT_ATTR(sdir-home-migrate, 0x4c), 303 HISI_PMU_EVENT_ATTR(edir-home-migrate, 0x4d), 304 NULL, 305 }; 306 307 static const struct attribute_group hisi_hha_pmu_events_group = { 308 .name = "events", 309 .attrs = hisi_hha_pmu_events_attr, 310 }; 311 312 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); 313 314 static struct attribute *hisi_hha_pmu_cpumask_attrs[] = { 315 &dev_attr_cpumask.attr, 316 NULL, 317 }; 318 319 static const struct attribute_group hisi_hha_pmu_cpumask_attr_group = { 320 .attrs = hisi_hha_pmu_cpumask_attrs, 321 }; 322 323 static const struct attribute_group *hisi_hha_pmu_attr_groups[] = { 324 &hisi_hha_pmu_format_group, 325 &hisi_hha_pmu_events_group, 326 &hisi_hha_pmu_cpumask_attr_group, 327 NULL, 328 }; 329 330 static const struct hisi_uncore_ops hisi_uncore_hha_ops = { 331 .write_evtype = hisi_hha_pmu_write_evtype, 332 .get_event_idx = hisi_uncore_pmu_get_event_idx, 333 .start_counters = hisi_hha_pmu_start_counters, 334 .stop_counters = hisi_hha_pmu_stop_counters, 335 .enable_counter = hisi_hha_pmu_enable_counter, 336 .disable_counter = hisi_hha_pmu_disable_counter, 337 .enable_counter_int = hisi_hha_pmu_enable_counter_int, 338 .disable_counter_int = hisi_hha_pmu_disable_counter_int, 339 .write_counter = hisi_hha_pmu_write_counter, 340 .read_counter = hisi_hha_pmu_read_counter, 341 }; 342 343 static int hisi_hha_pmu_dev_probe(struct platform_device *pdev, 344 struct hisi_pmu *hha_pmu) 345 { 346 int ret; 347 348 ret = hisi_hha_pmu_init_data(pdev, hha_pmu); 349 if (ret) 350 return ret; 351 352 ret = hisi_hha_pmu_init_irq(hha_pmu, pdev); 353 if (ret) 354 return ret; 355 356 hha_pmu->num_counters = HHA_NR_COUNTERS; 357 hha_pmu->counter_bits = 48; 358 hha_pmu->ops = &hisi_uncore_hha_ops; 359 hha_pmu->dev = &pdev->dev; 360 hha_pmu->on_cpu = -1; 361 hha_pmu->check_event = 0x65; 362 363 return 0; 364 } 365 366 static int hisi_hha_pmu_probe(struct platform_device *pdev) 367 { 368 struct hisi_pmu *hha_pmu; 369 char *name; 370 int ret; 371 372 hha_pmu = devm_kzalloc(&pdev->dev, sizeof(*hha_pmu), GFP_KERNEL); 373 if (!hha_pmu) 374 return -ENOMEM; 375 376 platform_set_drvdata(pdev, hha_pmu); 377 378 ret = hisi_hha_pmu_dev_probe(pdev, hha_pmu); 379 if (ret) 380 return ret; 381 382 ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, 383 &hha_pmu->node); 384 if (ret) { 385 dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); 386 return ret; 387 } 388 389 name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u", 390 hha_pmu->sccl_id, hha_pmu->index_id); 391 hha_pmu->pmu = (struct pmu) { 392 .name = name, 393 .module = THIS_MODULE, 394 .task_ctx_nr = perf_invalid_context, 395 .event_init = hisi_uncore_pmu_event_init, 396 .pmu_enable = hisi_uncore_pmu_enable, 397 .pmu_disable = hisi_uncore_pmu_disable, 398 .add = hisi_uncore_pmu_add, 399 .del = hisi_uncore_pmu_del, 400 .start = hisi_uncore_pmu_start, 401 .stop = hisi_uncore_pmu_stop, 402 .read = hisi_uncore_pmu_read, 403 .attr_groups = hisi_hha_pmu_attr_groups, 404 .capabilities = PERF_PMU_CAP_NO_EXCLUDE, 405 }; 406 407 ret = perf_pmu_register(&hha_pmu->pmu, name, -1); 408 if (ret) { 409 dev_err(hha_pmu->dev, "HHA PMU register failed!\n"); 410 cpuhp_state_remove_instance_nocalls( 411 CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node); 412 irq_set_affinity_hint(hha_pmu->irq, NULL); 413 } 414 415 return ret; 416 } 417 418 static int hisi_hha_pmu_remove(struct platform_device *pdev) 419 { 420 struct hisi_pmu *hha_pmu = platform_get_drvdata(pdev); 421 422 perf_pmu_unregister(&hha_pmu->pmu); 423 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, 424 &hha_pmu->node); 425 irq_set_affinity_hint(hha_pmu->irq, NULL); 426 427 return 0; 428 } 429 430 static struct platform_driver hisi_hha_pmu_driver = { 431 .driver = { 432 .name = "hisi_hha_pmu", 433 .acpi_match_table = ACPI_PTR(hisi_hha_pmu_acpi_match), 434 .suppress_bind_attrs = true, 435 }, 436 .probe = hisi_hha_pmu_probe, 437 .remove = hisi_hha_pmu_remove, 438 }; 439 440 static int __init hisi_hha_pmu_module_init(void) 441 { 442 int ret; 443 444 ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, 445 "AP_PERF_ARM_HISI_HHA_ONLINE", 446 hisi_uncore_pmu_online_cpu, 447 hisi_uncore_pmu_offline_cpu); 448 if (ret) { 449 pr_err("HHA PMU: Error setup hotplug, ret = %d;\n", ret); 450 return ret; 451 } 452 453 ret = platform_driver_register(&hisi_hha_pmu_driver); 454 if (ret) 455 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE); 456 457 return ret; 458 } 459 module_init(hisi_hha_pmu_module_init); 460 461 static void __exit hisi_hha_pmu_module_exit(void) 462 { 463 platform_driver_unregister(&hisi_hha_pmu_driver); 464 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE); 465 } 466 module_exit(hisi_hha_pmu_module_exit); 467 468 MODULE_DESCRIPTION("HiSilicon SoC HHA uncore PMU driver"); 469 MODULE_LICENSE("GPL v2"); 470 MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>"); 471 MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>"); 472