From 232eafd04f272ed69d97a250c50a7bbed4d2894c Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Mon, 16 Sep 2024 15:34:41 -0400 Subject: Support printing the runlist and channels on Ampere+ GPUs **Modifes the user API from `cat /proc/gpuX/runlist0` to `cat /proc/gpuX/runlist0/runlist` to support runlist-scoped registers** - Count number of runlists via Ampere-style PTOP parsing. - Create a ProcFS directory for each runlist, and create the runlist printing file in this directory. - Document the newly-added/-formatted Runlist RAM and Channel RAM registers. - Add a helper function `get_runlist_ram()` to obtain the location of each runlist's registers. - Support printing Ampere-style Channel RAM entries. Tested on Jetson Orin (ga10b), A100, H100, and AD102 (RTX 6000 Ada) --- runlist.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) (limited to 'runlist.c') diff --git a/runlist.c b/runlist.c index 2e9577d..7e6d292 100644 --- a/runlist.c +++ b/runlist.c @@ -14,6 +14,52 @@ // be enabled to print the runlist on the TX2. //#define FALLBACK_TO_PRAMIN +/* Get RunList RAM (RLRAM) offset for a runlist from the device topology + @param rl_id Which runlist to obtain [numbered in order of appearance in + the device topology (PTOP) registers] + @param rl_ram_off Location at which to store runlist private register + interface base address (PRI base); an offset into the BAR0 + register range. + @return 0 or -errno on error +*/ +int get_runlist_ram(struct nvdebug_state *g, int rl_id, uint32_t *rl_ram_off) { + int i; + int curr_rl_id = 0; + int ptop_size = NV_PTOP_DEVICE_INFO__SIZE_1_GA100(g); + // Each PTOP entry is composed of 1--3 subrows, and the fields available + // on each row vary. The runlist RAM location is only available on row 3 + int ptop_entry_subrow = 0; + ptop_device_info_ga100_t ptop_entry; + // Iterate through all PTOP entries + for (i = 0; i < ptop_size; i++) { + if ((ptop_entry.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_GA100(i))) == -1) + return -EIO; + // Skip empty entries + if (!ptop_entry.raw) + continue; + // If on subrow 3 (zero-base-index 2), runlist info is available + // Multiple engines may be associated with a single runlist, so + // multiple PTOP entries may refer to the same runlist. Only match when + // on the 0th-associated entry. + if (ptop_entry_subrow == 2 && ptop_entry.rleng_id == 0) { + // If this is the requested runlist, return it + if (curr_rl_id == rl_id) { + *rl_ram_off = (uint32_t)ptop_entry.runlist_pri_base << 10; + return 0; + } + // Otherwise, update our accounting of what the next runlist ID is + curr_rl_id++; + } + // Track if the next row is a subrow of the current entry + if (ptop_entry.has_next_entry) + ptop_entry_subrow += 1; + else + ptop_entry_subrow = 0; + } + // Search failed; requested index does not exist + return -EINVAL; +} + /* Get runlist head and info (incl. length) @param rl_id Which runlist to obtain? @param rl_iter Location at which to store output @@ -39,7 +85,7 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl runlist_target = rl.target; runlist_len = rl.len; printk(KERN_INFO "[nvdebug] Runlist %d for %x: %d entries @ %llx in %s (config raw: %#018llx)\n", - rl_id, g->chip_id, rl.len, runlist_iova, target_to_text(rl.target), rl.raw); + rl_id, g->chip_id, rl.len, runlist_iova, target_to_text(rl.target), rl.raw); } else if (g->chip_id < NV_CHIP_ID_AMPERE) { runlist_base_tu102_t base; runlist_submit_tu102_t submit; @@ -51,7 +97,26 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl runlist_target = base.target; runlist_len = submit.len; printk(KERN_INFO "[nvdebug] Runlist %d for %x: %d entries @ %llx in %s (config raw: %#018llx %#018llx)\n", - rl_id, g->chip_id, submit.len, runlist_iova, target_to_text(runlist_target), base.raw, submit.raw); + rl_id, g->chip_id, submit.len, runlist_iova, target_to_text(runlist_target), base.raw, submit.raw); + } else { + runlist_base_tu102_t base; + runlist_submit_tu102_t submit; + uint32_t runlist_pri_base; + // Runlist configurations are stored in per-runlist regions on Ampere+ + if ((err = get_runlist_ram(g, rl_id, &runlist_pri_base)) < 0) + return err; + // The runlist configuration region (RLRAM) contains Turing-like BASE + // and SUBMIT registers at static offsets + if ((base.raw = nvdebug_readq(g, runlist_pri_base + NV_RUNLIST_BASE_GA100)) == -1) + return -EIO; + if ((submit.raw = nvdebug_readq(g, runlist_pri_base + NV_RUNLIST_SUBMIT_GA100)) == -1) + return -EIO; + runlist_iova = ((uint64_t)base.ptr) << 12; + runlist_target = base.target; + runlist_len = submit.len; + printk(KERN_INFO "[nvdebug] Runlist %d for %x: %d entries @ %llx in %s (config raw: %#018llx %#018llx)\n", + rl_id, g->chip_id, submit.len, runlist_iova, target_to_text(runlist_target), base.raw, submit.raw); + rl_iter->runlist_pri_base = runlist_pri_base; } // Return early on an empty runlist if (!runlist_len) -- cgit v1.2.2