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

perf/arm_cspmu: nvidia: Add Tegra410 PCIE-TGT PMU

Adds PCIE-TGT PMU support in Tegra410 SOC. This PMU is
instanced in each root complex in the SOC and it captures
traffic originating from any source towards PCIE BAR and CXL
HDM range. The traffic can be filtered based on the
destination root port or target address range.

Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Besar Wicaksono and committed by
Will Deacon
3dd73022 bf585ba1

+398
+77
Documentation/admin-guide/perf/nvidia-tegra410-pmu.rst
··· 7 7 8 8 * Unified Coherence Fabric (UCF) 9 9 * PCIE 10 + * PCIE-TGT 10 11 11 12 PMU Driver 12 13 ---------- ··· 213 212 214 213 perf stat -a -e nvidia_pcie_pmu_0_rc_4/event=0x4,src_bdf=0x0180,src_bdf_en=0x1/ 215 214 215 + .. _NVIDIA_T410_PCIE_PMU_RC_Mapping_Section: 216 + 217 + Mapping the RC# to lspci segment number 218 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 219 + 216 220 Mapping the RC# to lspci segment number can be non-trivial; hence a new NVIDIA 217 221 Designated Vendor Specific Capability (DVSEC) register is added into the PCIE config space 218 222 for each RP. This DVSEC has vendor id "10de" and DVSEC id of "0x4". The DVSEC register ··· 273 267 000d:40:00.0: Bus=40, Segment=0d, RP=01, RC=04, Socket=01 274 268 000d:c0:00.0: Bus=c0, Segment=0d, RP=02, RC=04, Socket=01 275 269 000e:00:00.0: Bus=00, Segment=0e, RP=00, RC=05, Socket=01 270 + 271 + PCIE-TGT PMU 272 + ------------ 273 + 274 + This PMU is located in the SOC fabric connecting the PCIE root complex (RC) and 275 + the memory subsystem. It monitors traffic targeting PCIE BAR and CXL HDM ranges. 276 + There is one PCIE-TGT PMU per PCIE RC in the SoC. Each RC in Tegra410 SoC can 277 + have up to 16 lanes that can be bifurcated into up to 8 root ports (RP). The PMU 278 + provides RP filter to count PCIE BAR traffic to each RP and address filter to 279 + count access to PCIE BAR or CXL HDM ranges. The details of the filters are 280 + described in the following sections. 281 + 282 + Mapping the RC# to lspci segment number is similar to the PCIE PMU. Please see 283 + :ref:`NVIDIA_T410_PCIE_PMU_RC_Mapping_Section` for more info. 284 + 285 + The events and configuration options of this PMU device are available in sysfs, 286 + see /sys/bus/event_source/devices/nvidia_pcie_tgt_pmu_<socket-id>_rc_<pcie-rc-id>. 287 + 288 + The events in this PMU can be used to measure bandwidth and utilization: 289 + 290 + * rd_req: count the number of read requests to PCIE. 291 + * wr_req: count the number of write requests to PCIE. 292 + * rd_bytes: count the number of bytes transferred by rd_req. 293 + * wr_bytes: count the number of bytes transferred by wr_req. 294 + * cycles: count the clock cycles of SOC fabric connected to the PCIE interface. 295 + 296 + The average bandwidth is calculated as:: 297 + 298 + AVG_RD_BANDWIDTH_IN_GBPS = RD_BYTES / ELAPSED_TIME_IN_NS 299 + AVG_WR_BANDWIDTH_IN_GBPS = WR_BYTES / ELAPSED_TIME_IN_NS 300 + 301 + The average request rate is calculated as:: 302 + 303 + AVG_RD_REQUEST_RATE = RD_REQ / CYCLES 304 + AVG_WR_REQUEST_RATE = WR_REQ / CYCLES 305 + 306 + The PMU events can be filtered based on the destination root port or target 307 + address range. Filtering based on RP is only available for PCIE BAR traffic. 308 + Address filter works for both PCIE BAR and CXL HDM ranges. These filters can be 309 + found in sysfs, see 310 + /sys/bus/event_source/devices/nvidia_pcie_tgt_pmu_<socket-id>_rc_<pcie-rc-id>/format/. 311 + 312 + Destination filter settings: 313 + 314 + * dst_rp_mask: bitmask to select the root port(s) to monitor. E.g. "dst_rp_mask=0xFF" 315 + corresponds to all root ports (from 0 to 7) in the PCIE RC. Note that this filter is 316 + only available for PCIE BAR traffic. 317 + * dst_addr_base: BAR or CXL HDM filter base address. 318 + * dst_addr_mask: BAR or CXL HDM filter address mask. 319 + * dst_addr_en: enable BAR or CXL HDM address range filter. If this is set, the 320 + address range specified by "dst_addr_base" and "dst_addr_mask" will be used to filter 321 + the PCIE BAR and CXL HDM traffic address. The PMU uses the following comparison 322 + to determine if the traffic destination address falls within the filter range:: 323 + 324 + (txn's addr & dst_addr_mask) == (dst_addr_base & dst_addr_mask) 325 + 326 + If the comparison succeeds, then the event will be counted. 327 + 328 + If the destination filter is not specified, the RP filter will be configured by default 329 + to count PCIE BAR traffic to all root ports. 330 + 331 + Example usage: 332 + 333 + * Count event id 0x0 to root port 0 and 1 of PCIE RC-0 on socket 0:: 334 + 335 + perf stat -a -e nvidia_pcie_tgt_pmu_0_rc_0/event=0x0,dst_rp_mask=0x3/ 336 + 337 + * Count event id 0x1 for accesses to PCIE BAR or CXL HDM address range 338 + 0x10000 to 0x100FF on socket 0's PCIE RC-1:: 339 + 340 + perf stat -a -e nvidia_pcie_tgt_pmu_0_rc_1/event=0x1,dst_addr_base=0x10000,dst_addr_mask=0xFFF00,dst_addr_en=0x1/
+321
drivers/perf/arm_cspmu/nvidia_cspmu.c
··· 42 42 #define NV_PCIE_V2_FILTER2_DST GENMASK_ULL(NV_PCIE_V2_DST_COUNT - 1, 0) 43 43 #define NV_PCIE_V2_FILTER2_DEFAULT NV_PCIE_V2_FILTER2_DST 44 44 45 + #define NV_PCIE_TGT_PORT_COUNT 8ULL 46 + #define NV_PCIE_TGT_EV_TYPE_CC 0x4 47 + #define NV_PCIE_TGT_EV_TYPE_COUNT 3ULL 48 + #define NV_PCIE_TGT_EV_TYPE_MASK GENMASK_ULL(NV_PCIE_TGT_EV_TYPE_COUNT - 1, 0) 49 + #define NV_PCIE_TGT_FILTER2_MASK GENMASK_ULL(NV_PCIE_TGT_PORT_COUNT, 0) 50 + #define NV_PCIE_TGT_FILTER2_PORT GENMASK_ULL(NV_PCIE_TGT_PORT_COUNT - 1, 0) 51 + #define NV_PCIE_TGT_FILTER2_ADDR_EN BIT(NV_PCIE_TGT_PORT_COUNT) 52 + #define NV_PCIE_TGT_FILTER2_ADDR GENMASK_ULL(15, NV_PCIE_TGT_PORT_COUNT) 53 + #define NV_PCIE_TGT_FILTER2_DEFAULT NV_PCIE_TGT_FILTER2_PORT 54 + 55 + #define NV_PCIE_TGT_ADDR_COUNT 8ULL 56 + #define NV_PCIE_TGT_ADDR_STRIDE 20 57 + #define NV_PCIE_TGT_ADDR_CTRL 0xD38 58 + #define NV_PCIE_TGT_ADDR_BASE_LO 0xD3C 59 + #define NV_PCIE_TGT_ADDR_BASE_HI 0xD40 60 + #define NV_PCIE_TGT_ADDR_MASK_LO 0xD44 61 + #define NV_PCIE_TGT_ADDR_MASK_HI 0xD48 62 + 45 63 #define NV_GENERIC_FILTER_ID_MASK GENMASK_ULL(31, 0) 46 64 47 65 #define NV_PRODID_MASK (PMIIDR_PRODUCTID | PMIIDR_VARIANT | PMIIDR_REVISION) ··· 203 185 NULL 204 186 }; 205 187 188 + static struct attribute *pcie_tgt_pmu_event_attrs[] = { 189 + ARM_CSPMU_EVENT_ATTR(rd_bytes, 0x0), 190 + ARM_CSPMU_EVENT_ATTR(wr_bytes, 0x1), 191 + ARM_CSPMU_EVENT_ATTR(rd_req, 0x2), 192 + ARM_CSPMU_EVENT_ATTR(wr_req, 0x3), 193 + ARM_CSPMU_EVENT_ATTR(cycles, NV_PCIE_TGT_EV_TYPE_CC), 194 + NULL 195 + }; 196 + 206 197 static struct attribute *generic_pmu_event_attrs[] = { 207 198 ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT), 208 199 NULL, ··· 262 235 ARM_CSPMU_FORMAT_ATTR(dst_loc_pcie_p2p, "config2:2"), 263 236 ARM_CSPMU_FORMAT_ATTR(dst_loc_pcie_cxl, "config2:3"), 264 237 ARM_CSPMU_FORMAT_ATTR(dst_rem, "config2:4"), 238 + NULL 239 + }; 240 + 241 + static struct attribute *pcie_tgt_pmu_format_attrs[] = { 242 + ARM_CSPMU_FORMAT_ATTR(event, "config:0-2"), 243 + ARM_CSPMU_FORMAT_ATTR(dst_rp_mask, "config:3-10"), 244 + ARM_CSPMU_FORMAT_ATTR(dst_addr_en, "config:11"), 245 + ARM_CSPMU_FORMAT_ATTR(dst_addr_base, "config1:0-63"), 246 + ARM_CSPMU_FORMAT_ATTR(dst_addr_mask, "config2:0-63"), 265 247 NULL 266 248 }; 267 249 ··· 513 477 return 0; 514 478 } 515 479 480 + struct pcie_tgt_addr_filter { 481 + u32 refcount; 482 + u64 base; 483 + u64 mask; 484 + }; 485 + 486 + struct pcie_tgt_data { 487 + struct pcie_tgt_addr_filter addr_filter[NV_PCIE_TGT_ADDR_COUNT]; 488 + void __iomem *addr_filter_reg; 489 + }; 490 + 491 + #if defined(CONFIG_ACPI) && defined(CONFIG_ARM64) 492 + static int pcie_tgt_init_data(struct arm_cspmu *cspmu) 493 + { 494 + int ret; 495 + struct acpi_device *adev; 496 + struct pcie_tgt_data *data; 497 + struct list_head resource_list; 498 + struct resource_entry *rentry; 499 + struct nv_cspmu_ctx *ctx = to_nv_cspmu_ctx(cspmu); 500 + struct device *dev = cspmu->dev; 501 + 502 + data = devm_kzalloc(dev, sizeof(struct pcie_tgt_data), GFP_KERNEL); 503 + if (!data) 504 + return -ENOMEM; 505 + 506 + adev = arm_cspmu_acpi_dev_get(cspmu); 507 + if (!adev) { 508 + dev_err(dev, "failed to get associated PCIE-TGT device\n"); 509 + return -ENODEV; 510 + } 511 + 512 + INIT_LIST_HEAD(&resource_list); 513 + ret = acpi_dev_get_memory_resources(adev, &resource_list); 514 + if (ret < 0) { 515 + dev_err(dev, "failed to get PCIE-TGT device memory resources\n"); 516 + acpi_dev_put(adev); 517 + return ret; 518 + } 519 + 520 + rentry = list_first_entry_or_null( 521 + &resource_list, struct resource_entry, node); 522 + if (rentry) { 523 + data->addr_filter_reg = devm_ioremap_resource(dev, rentry->res); 524 + ret = 0; 525 + } 526 + 527 + if (IS_ERR(data->addr_filter_reg)) { 528 + dev_err(dev, "failed to get address filter resource\n"); 529 + ret = PTR_ERR(data->addr_filter_reg); 530 + } 531 + 532 + acpi_dev_free_resource_list(&resource_list); 533 + acpi_dev_put(adev); 534 + 535 + ctx->data = data; 536 + 537 + return ret; 538 + } 539 + #else 540 + static int pcie_tgt_init_data(struct arm_cspmu *cspmu) 541 + { 542 + return -ENODEV; 543 + } 544 + #endif 545 + 546 + static struct pcie_tgt_data *pcie_tgt_get_data(struct arm_cspmu *cspmu) 547 + { 548 + struct nv_cspmu_ctx *ctx = to_nv_cspmu_ctx(cspmu); 549 + 550 + return ctx->data; 551 + } 552 + 553 + /* Find the first available address filter slot. */ 554 + static int pcie_tgt_find_addr_idx(struct arm_cspmu *cspmu, u64 base, u64 mask, 555 + bool is_reset) 556 + { 557 + int i; 558 + struct pcie_tgt_data *data = pcie_tgt_get_data(cspmu); 559 + 560 + for (i = 0; i < NV_PCIE_TGT_ADDR_COUNT; i++) { 561 + if (!is_reset && data->addr_filter[i].refcount == 0) 562 + return i; 563 + 564 + if (data->addr_filter[i].base == base && 565 + data->addr_filter[i].mask == mask) 566 + return i; 567 + } 568 + 569 + return -ENODEV; 570 + } 571 + 572 + static u32 pcie_tgt_pmu_event_filter(const struct perf_event *event) 573 + { 574 + u32 filter; 575 + 576 + filter = (event->attr.config >> NV_PCIE_TGT_EV_TYPE_COUNT) & 577 + NV_PCIE_TGT_FILTER2_MASK; 578 + 579 + return filter; 580 + } 581 + 582 + static bool pcie_tgt_pmu_addr_en(const struct perf_event *event) 583 + { 584 + u32 filter = pcie_tgt_pmu_event_filter(event); 585 + 586 + return FIELD_GET(NV_PCIE_TGT_FILTER2_ADDR_EN, filter) != 0; 587 + } 588 + 589 + static u32 pcie_tgt_pmu_port_filter(const struct perf_event *event) 590 + { 591 + u32 filter = pcie_tgt_pmu_event_filter(event); 592 + 593 + return FIELD_GET(NV_PCIE_TGT_FILTER2_PORT, filter); 594 + } 595 + 596 + static u64 pcie_tgt_pmu_dst_addr_base(const struct perf_event *event) 597 + { 598 + return event->attr.config1; 599 + } 600 + 601 + static u64 pcie_tgt_pmu_dst_addr_mask(const struct perf_event *event) 602 + { 603 + return event->attr.config2; 604 + } 605 + 606 + static int pcie_tgt_pmu_validate_event(struct arm_cspmu *cspmu, 607 + struct perf_event *new_ev) 608 + { 609 + u64 base, mask; 610 + int idx; 611 + 612 + if (!pcie_tgt_pmu_addr_en(new_ev)) 613 + return 0; 614 + 615 + /* Make sure there is a slot available for the address filter. */ 616 + base = pcie_tgt_pmu_dst_addr_base(new_ev); 617 + mask = pcie_tgt_pmu_dst_addr_mask(new_ev); 618 + idx = pcie_tgt_find_addr_idx(cspmu, base, mask, false); 619 + if (idx < 0) 620 + return -EINVAL; 621 + 622 + return 0; 623 + } 624 + 625 + static void pcie_tgt_pmu_config_addr_filter(struct arm_cspmu *cspmu, 626 + bool en, u64 base, u64 mask, int idx) 627 + { 628 + struct pcie_tgt_data *data; 629 + struct pcie_tgt_addr_filter *filter; 630 + void __iomem *filter_reg; 631 + 632 + data = pcie_tgt_get_data(cspmu); 633 + filter = &data->addr_filter[idx]; 634 + filter_reg = data->addr_filter_reg + (idx * NV_PCIE_TGT_ADDR_STRIDE); 635 + 636 + if (en) { 637 + filter->refcount++; 638 + if (filter->refcount == 1) { 639 + filter->base = base; 640 + filter->mask = mask; 641 + 642 + writel(lower_32_bits(base), filter_reg + NV_PCIE_TGT_ADDR_BASE_LO); 643 + writel(upper_32_bits(base), filter_reg + NV_PCIE_TGT_ADDR_BASE_HI); 644 + writel(lower_32_bits(mask), filter_reg + NV_PCIE_TGT_ADDR_MASK_LO); 645 + writel(upper_32_bits(mask), filter_reg + NV_PCIE_TGT_ADDR_MASK_HI); 646 + writel(1, filter_reg + NV_PCIE_TGT_ADDR_CTRL); 647 + } 648 + } else { 649 + filter->refcount--; 650 + if (filter->refcount == 0) { 651 + writel(0, filter_reg + NV_PCIE_TGT_ADDR_CTRL); 652 + writel(0, filter_reg + NV_PCIE_TGT_ADDR_BASE_LO); 653 + writel(0, filter_reg + NV_PCIE_TGT_ADDR_BASE_HI); 654 + writel(0, filter_reg + NV_PCIE_TGT_ADDR_MASK_LO); 655 + writel(0, filter_reg + NV_PCIE_TGT_ADDR_MASK_HI); 656 + 657 + filter->base = 0; 658 + filter->mask = 0; 659 + } 660 + } 661 + } 662 + 663 + static void pcie_tgt_pmu_set_ev_filter(struct arm_cspmu *cspmu, 664 + const struct perf_event *event) 665 + { 666 + bool addr_filter_en; 667 + int idx; 668 + u32 filter2_val, filter2_offset, port_filter; 669 + u64 base, mask; 670 + 671 + filter2_val = 0; 672 + filter2_offset = PMEVFILT2R + (4 * event->hw.idx); 673 + 674 + addr_filter_en = pcie_tgt_pmu_addr_en(event); 675 + if (addr_filter_en) { 676 + base = pcie_tgt_pmu_dst_addr_base(event); 677 + mask = pcie_tgt_pmu_dst_addr_mask(event); 678 + idx = pcie_tgt_find_addr_idx(cspmu, base, mask, false); 679 + 680 + if (idx < 0) { 681 + dev_err(cspmu->dev, 682 + "Unable to find a slot for address filtering\n"); 683 + writel(0, cspmu->base0 + filter2_offset); 684 + return; 685 + } 686 + 687 + /* Configure address range filter registers.*/ 688 + pcie_tgt_pmu_config_addr_filter(cspmu, true, base, mask, idx); 689 + 690 + /* Config the counter to use the selected address filter slot. */ 691 + filter2_val |= FIELD_PREP(NV_PCIE_TGT_FILTER2_ADDR, 1U << idx); 692 + } 693 + 694 + port_filter = pcie_tgt_pmu_port_filter(event); 695 + 696 + /* Monitor all ports if no filter is selected. */ 697 + if (!addr_filter_en && port_filter == 0) 698 + port_filter = NV_PCIE_TGT_FILTER2_PORT; 699 + 700 + filter2_val |= FIELD_PREP(NV_PCIE_TGT_FILTER2_PORT, port_filter); 701 + 702 + writel(filter2_val, cspmu->base0 + filter2_offset); 703 + } 704 + 705 + static void pcie_tgt_pmu_reset_ev_filter(struct arm_cspmu *cspmu, 706 + const struct perf_event *event) 707 + { 708 + bool addr_filter_en; 709 + u64 base, mask; 710 + int idx; 711 + 712 + addr_filter_en = pcie_tgt_pmu_addr_en(event); 713 + if (!addr_filter_en) 714 + return; 715 + 716 + base = pcie_tgt_pmu_dst_addr_base(event); 717 + mask = pcie_tgt_pmu_dst_addr_mask(event); 718 + idx = pcie_tgt_find_addr_idx(cspmu, base, mask, true); 719 + 720 + if (idx < 0) { 721 + dev_err(cspmu->dev, 722 + "Unable to find the address filter slot to reset\n"); 723 + return; 724 + } 725 + 726 + pcie_tgt_pmu_config_addr_filter(cspmu, false, base, mask, idx); 727 + } 728 + 729 + static u32 pcie_tgt_pmu_event_type(const struct perf_event *event) 730 + { 731 + return event->attr.config & NV_PCIE_TGT_EV_TYPE_MASK; 732 + } 733 + 734 + static bool pcie_tgt_pmu_is_cycle_counter_event(const struct perf_event *event) 735 + { 736 + u32 event_type = pcie_tgt_pmu_event_type(event); 737 + 738 + return event_type == NV_PCIE_TGT_EV_TYPE_CC; 739 + } 740 + 516 741 enum nv_cspmu_name_fmt { 517 742 NAME_FMT_GENERIC, 518 743 NAME_FMT_SOCKET, ··· 916 619 } 917 620 }, 918 621 { 622 + .prodid = 0x10700000, 623 + .prodid_mask = NV_PRODID_MASK, 624 + .name_pattern = "nvidia_pcie_tgt_pmu_%u_rc_%u", 625 + .name_fmt = NAME_FMT_SOCKET_INST, 626 + .template_ctx = { 627 + .event_attr = pcie_tgt_pmu_event_attrs, 628 + .format_attr = pcie_tgt_pmu_format_attrs, 629 + .filter_mask = 0x0, 630 + .filter_default_val = 0x0, 631 + .filter2_mask = NV_PCIE_TGT_FILTER2_MASK, 632 + .filter2_default_val = NV_PCIE_TGT_FILTER2_DEFAULT, 633 + .init_data = pcie_tgt_init_data 634 + }, 635 + .ops = { 636 + .is_cycle_counter_event = pcie_tgt_pmu_is_cycle_counter_event, 637 + .event_type = pcie_tgt_pmu_event_type, 638 + .validate_event = pcie_tgt_pmu_validate_event, 639 + .set_ev_filter = pcie_tgt_pmu_set_ev_filter, 640 + .reset_ev_filter = pcie_tgt_pmu_reset_ev_filter, 641 + } 642 + }, 643 + { 919 644 .prodid = 0, 920 645 .prodid_mask = 0, 921 646 .name_pattern = "nvidia_uncore_pmu_%u", ··· 1029 710 1030 711 /* NVIDIA specific callbacks. */ 1031 712 SET_OP(validate_event, impl_ops, match, NULL); 713 + SET_OP(event_type, impl_ops, match, NULL); 714 + SET_OP(is_cycle_counter_event, impl_ops, match, NULL); 1032 715 SET_OP(set_cc_filter, impl_ops, match, nv_cspmu_set_cc_filter); 1033 716 SET_OP(set_ev_filter, impl_ops, match, nv_cspmu_set_ev_filter); 1034 717 SET_OP(reset_ev_filter, impl_ops, match, NULL);