public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
From: Claude Code Review Bot <claude-review@example.com>
To: dri-devel-reviews@example.com
Subject: Claude review: accel/amdxdna: Read real-time clock frequencies
Date: Sun, 12 Apr 2026 14:21:10 +1000	[thread overview]
Message-ID: <review-patch1-20260406220526.4027917-1-lizhi.hou@amd.com> (raw)
In-Reply-To: <20260406220526.4027917-1-lizhi.hou@amd.com>

Patch Review

**1. Potential field-name swap in `npu4_update_counters` (npu4_regs.c) — needs clarification**

```c
ndev->npuclk_freq = npu_metrics.mpnpuclk_freq;
ndev->hclk_freq = npu_metrics.npuclk_freq;
```

From `include/linux/amd-pmf-io.h`, the PMF struct documents:
- `npuclk_freq` — "NPU clock frequency [MHz]"
- `mpnpuclk_freq` — "MPNPU [MHz]"

In the driver (`npu4_set_dpm`), the existing mapping is:
```c
ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;  // MP-NPU clock
ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;      // H clock
```

So this maps PMF's `mpnpuclk_freq` → driver's `npuclk_freq` (MP-NPU), and PMF's `npuclk_freq` → driver's `hclk_freq` (H clock). The cross-wiring of names is extremely confusing. Even if this mapping is hardware-correct, a comment explaining why `npu_metrics.npuclk_freq` maps to `ndev->hclk_freq` (and not `npuclk_freq`) would prevent future maintenance mistakes.

**2. `aie2_update_counters` macro silently discards errors (aie2_pci.h)**

```c
#define aie2_update_counters(ndev)                  \
({                                                  \
    typeof(ndev) _ndev = ndev;                      \
    if (_ndev->priv->hw_ops->update_counters)       \
        _ndev->priv->hw_ops->update_counters(_ndev);\
})
```

This macro has two problems:

- The return value of `update_counters()` is silently discarded. If PMF is unavailable (`CONFIG_AMD_PMF=n`), `AIE2_GET_PMF_NPU_METRICS` returns `-EOPNOTSUPP`, and the caller proceeds to report stale/previous frequency data to userspace with no indication it's stale.
- The macro itself is a statement expression but its value is the result of the `if` statement, which is `void`. Callers cannot check for errors even if they wanted to.

At minimum, consider making this return `int` and propagating the error, or at least adding `dev_dbg` on failure so the silent fallback to stale data is discoverable during debugging:

```c
#define aie2_update_counters(ndev)                          \
({                                                          \
    typeof(ndev) _ndev = ndev;                              \
    int _ret = 0;                                           \
    if (_ndev->priv->hw_ops->update_counters)               \
        _ret = _ndev->priv->hw_ops->update_counters(_ndev); \
    _ret;                                                   \
})
```

**3. `npu4_update_counters` doesn't update `max_tops` (npu4_regs.c)**

Compare with `npu4_set_dpm`:
```c
ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->priv->dpm_clk_tbl[ndev->max_dpm_level].hclk);
ndev->curr_tops = NPU4_DPM_TOPS(ndev, ndev->hclk_freq);
```

But `npu4_update_counters` only updates `curr_tops`:
```c
ndev->curr_tops = NPU4_DPM_TOPS(ndev, ndev->hclk_freq);
```

This is probably intentional (max TOPS shouldn't change at runtime), but `aie2_query_resource_info` reads `ndev->max_tops` right after calling `aie2_update_counters`. If this is deliberate, a brief comment explaining that `max_tops` is set once in `set_dpm` and doesn't need runtime refresh would help reviewers.

**4. No locking around field updates in `npu4_update_counters`**

`npu4_update_counters` modifies `ndev->npuclk_freq`, `ndev->hclk_freq`, and `ndev->curr_tops` without any visible locking. These same fields are also written by `npu4_set_dpm` (called via `aie2_pm_set_dpm` from ioctl paths). If a DPM-level change races with a clock metadata query, the reported values could be inconsistent (e.g., `npuclk_freq` from PMF but `curr_tops` computed from a DPM-table hclk). This may be an existing issue, but the new call sites in `aie2_get_clock_metadata` and `aie2_query_resource_info` widen the race window.

**5. Compound literal vs named constant inconsistency (npu1_regs.c)**

```c
.hw_ops = &(const struct aie2_hw_ops) {
    .set_dpm = npu1_set_dpm,
},
```

NPU1 uses an anonymous compound literal while NPU4/5/6 use the named `npu4_hw_ops`. For consistency and debuggability, consider defining a `npu1_hw_ops` named constant as well.

**6. Missing trailing commas (npu4_regs.c, npu5_regs.c, npu6_regs.c)**

```c
.hw_ops = &npu4_hw_ops
```

The kernel coding style convention is to include trailing commas after the last struct member initializer, to reduce future diff noise. The original code had them.

**7. NPU5 and NPU6 inherit `update_counters` (npu5_regs.c, npu6_regs.c)**

By pointing `.hw_ops = &npu4_hw_ops`, npu5 and npu6 now also get `npu4_update_counters`. This means PMF metrics queries will be made for these NPU generations too. Is the PMF interface guaranteed to work the same way across NPU4/5/6? The commit message doesn't address this.

**8. Patch should be split**

This patch bundles a mechanical refactor (struct → pointer, making `npu4_set_dpm` static, sharing `npu4_hw_ops`) with a functional change (new `update_counters` callback and its call sites). Kernel convention is to separate these:
- Patch 1: Refactor `hw_ops` from embedded struct to const pointer
- Patch 2: Add `update_counters` callback and PMF integration

This aids bisection if the PMF integration causes issues.

**9. `NPU4_DPM_TOPS` macro simplification is correct (npu4_regs.c)**

The old macro:
```c
#define NPU4_DPM_TOPS(ndev, dpm_level) \
({ \
    typeof(ndev) _ndev = ndev; \
    (4096 * (_ndev)->total_col * \
     (_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \
})
```

The new macro:
```c
#define NPU4_DPM_TOPS(ndev, hclk) (4096 * (ndev)->total_col * (hclk) / 1000000)
```

This is a good simplification. Taking the raw hclk value as input rather than a DPM level index makes the macro more reusable (needed for `update_counters` which gets hclk from PMF, not from the DPM table). The removal of `typeof` guard is safe since `ndev` is only dereferenced once and all callers pass a simple pointer.

---
Generated by Claude Code Patch Reviewer

      parent reply	other threads:[~2026-04-12  4:21 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-06 22:05 [PATCH V1] accel/amdxdna: Read real-time clock frequencies Lizhi Hou
2026-04-11  3:33 ` Mario Limonciello
2026-04-12  4:21 ` Claude review: " Claude Code Review Bot
2026-04-12  4:21 ` Claude Code Review Bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=review-patch1-20260406220526.4027917-1-lizhi.hou@amd.com \
    --to=claude-review@example.com \
    --cc=dri-devel-reviews@example.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox