Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3e1ced5
drm/asahi: g15: m3: account PB backing and re-initialization in the g…
malik-na Oct 22, 2026
3a7dea2
drm/asahi: g15: m3: back the PB in 16 MiB chunks after the reply, wit…
malik-na Oct 22, 2026
f637d67
drm/asahi: g15: m3: start the parameter buffer at 64 blocks
malik-na Oct 22, 2026
d2ad713
drm/asahi: g15: m3: reclaim the parameter buffer when the engine is idle
malik-na Oct 22, 2026
330a11a
drm/asahi: g15: m3: re-initialize the parameter buffer at a client bo…
malik-na Oct 22, 2026
ddd0598
drm/asahi: g15: m3: bound the CDM stream walk by bytes, not by 8192 r…
malik-na Oct 22, 2026
6ce5b84
drm/asahi: g15: select the Rust firmware loader abstractions
malik-na Oct 22, 2026
48142e6
drm/asahi: g15: m3: run the PB reclaim check after the idle time with…
malik-na Oct 22, 2026
2c42847
drm/asahi: g15: say when the boot loader left the GPU node disabled
malik-na Oct 22, 2026
bb1b0c8
tools/asahi: run-host-tests: give device-tree tests a built dtc
RyanTheTide Nov 1, 2026
bc4f744
arm64: dts: apple: t6030: guard static PMP nodes
erykwieliczko Oct 24, 2026
aaba39e
drm/asahi: g15: match UAT reservations with unit addresses
erykwieliczko Oct 24, 2026
1cf5527
drm/asahi: g15: pin the module with try_module_get before firmware start
chriskearney Oct 26, 2026
068c2fa
drm/asahi: g15: t6031: build the J516C board data without a board file
malik-na Oct 27, 2026
a18d931
tools/asahi: g15-maintained-handoff-tests: define the sensor-row count
malik-na Oct 27, 2026
bcb0225
drm/asahi: g15: t6031: log the J516C hardware record digest
malik-na Oct 28, 2026
c45c861
drm/asahi: wrap G15 stamps through zero
erykwieliczko Oct 25, 2026
2db2e9f
drm/asahi: bind G15 slots at publication
erykwieliczko Oct 25, 2026
2a3ddc7
drm/asahi: lock G15 mappings once per submit
erykwieliczko Oct 26, 2026
6e5b91a
soc: apple: report T6030 GPU power to PMP
erykwieliczko Oct 26, 2026
0652b14
tests/asahi: follow G15 publication binding interfaces
chriskearney Oct 28, 2026
e91fc1b
tests/asahi: model GFX report calls in PMP bridge fixtures
chriskearney Oct 28, 2026
6ec4d35
drm/asahi: g15: start T6031 after its native display, then autoload it
chriskearney Oct 27, 2026
50308e7
tools/asahi: t6030 display admission tests: follow the shared display…
chriskearney Oct 27, 2026
dfc9168
soc: apple: t6030-display-gate: default the T6031 native display on J…
chriskearney Oct 27, 2026
ca05e40
drm/asahi: g15: say when the T6031 GPU waits on an enabled display
chriskearney Oct 28, 2026
cc35ef2
drm/asahi: g15: build Board::DeviceTree only with the G15 backend
erykwieliczko Oct 28, 2026
35d8cd7
drm/asahi: build Uat::try_bind only with the G15 backend
erykwieliczko Oct 28, 2026
af28934
drm/asahi: build VmReadGuard::covers_range only with the G15 backend
erykwieliczko Oct 28, 2026
deb10a5
tests: asahi: synchronize tbnet refill-worker teardown checks
chriskearney Oct 24, 2026
bd0eec9
tests: asahi: scan default T6030 trees for PMP compatibles
chriskearney Oct 24, 2026
986132e
drm/asahi: g15: pin the B0 firmware on the J514S
JeppeBylov Oct 26, 2026
83ca860
test: asahi: refresh the J514S firmware row golden pins
chriskearney Oct 30, 2026
7beb9f2
drm/asahi: expose raw firmware statistics through debugfs
joshuaswarren Oct 29, 2026
8150f30
Documentation/ABI: describe the asahi_stats debugfs file
joshuaswarren Oct 29, 2026
ffeecc8
Documentation/ABI: fix stats counter wording and contact line
joshuaswarren Oct 29, 2026
553f083
drm/asahi: only create the stats file with CONFIG_DEBUG_FS
joshuaswarren Oct 29, 2026
14432bc
tools/asahi: run the raw statistics export test with the host tests
RyanTheTide Nov 1, 2026
1761ce5
drm/asahi: g15: renumber the TA/FS stamps before the TA stamp wraps
Oct 25, 2026
433c287
drm/asahi: g15: drain the flights inside the stamp renumbering margin
Oct 25, 2026
69617c1
drm/asahi: g15: renumber the compute stamp before it wraps
Oct 29, 2026
d8bd85f
drm/asahi: g15: show what is left before the stamps wrap in the stats
Oct 29, 2026
9f2b5e6
tools/asahi: g15-display-order-tests: model the system-sleep hold
chriskearney Oct 30, 2026
c0cd9aa
drm/asahi: g15: m3: make the PB start and idle reclaim fixed driver v…
RyanTheTide Nov 1, 2026
a91ef82
drm/asahi: g15: renumber the stamps at a fixed margin, without module…
RyanTheTide Nov 1, 2026
444919e
selftests: asahi-m4: follow Uat::bind() into bind_inner()
RyanTheTide Nov 1, 2026
0c73800
Merge aurora-wip into omacom-sync/g15
RyanTheTide Nov 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/host-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ jobs:
command -v "$p" >/dev/null || need="$need $p"
done
command -v "ld.lld-$CLANG_VERSION" >/dev/null || need="$need lld-$CLANG_VERSION"
# Device-tree tests read the built trees with fdtget.
command -v fdtget >/dev/null || need="$need device-tree-compiler"
dpkg -s "libclang-rt-$CLANG_VERSION-dev" >/dev/null 2>&1 || need="$need libclang-rt-$CLANG_VERSION-dev"
if [ -n "$need" ]; then
sudo apt-get update -q
Expand Down
47 changes: 47 additions & 0 deletions Documentation/ABI/testing/debugfs-driver-asahi-stats
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
What: /sys/kernel/debug/dri/<N>/asahi_stats
Date: October 2026
Contact: Ryan Murray <ryan@aurorasilicon.org>
Description:
Read-only, root-only dump of the raw AGX firmware statistics
that the drm/asahi driver receives on its statistics channel.
The driver stores the latest message of each kind and prints
it unchanged. It does not compute utilization or any other
derived value.

The file is created in the debugfs directory of the DRM
device when the device is registered. It also appears under
the other names of that directory (dri/128 and the platform
device name, for example dri/406400000.gpu).

The format is ASCII text, one line per record:

- line 1: asahi_stats_v1, the format tag. A reader must check it.
- line 2: device=<platform device name>
- line 3: now_ns=<monotonic time of the read, nanoseconds>
- line 4: messages count=<number of statistics messages received>
- then one line per message kind, in this order: power,
power_on, power_off, utilization, avg_power, temperature,
power_state, fw_busy, pstate, temp_sensor.

A kind line is "<kind> count=<n>" followed, when n is not 0,
by " captured_ns=<ns of the last message>" and the fields of
that kind as key=value pairs:

- power: power
- power_on: off_time
- power_off: on_time
- utilization: timestamp, util1, util2, util3, util4
- avg_power: active_cs, unk2, unk3, unk4, avg_power
- temperature: raw_value, scale, tmin, tmax
- power_state: timestamp, last_busy_ts, active, poweroff,
unk1, pstate, unk2, unk3
- fw_busy: timestamp, busy
- pstate: ps_min, unk1, ps_max, unk2
- temp_sensor: sensor_id, raw_value, scale, tmin, tmax

All counts are cumulative since the driver bound the device. A rate needs two reads.
The values are the raw firmware values. Their units and the
meaning of the util*, unk* fields are not established. A kind
that was never received prints count=0 and no payload. Keys
may be added in later versions of the format tag; readers
must ignore keys they do not know.
4 changes: 4 additions & 0 deletions arch/arm64/boot/dts/apple/t6030.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,8 @@
#clock-cells = <1>;
};

/* The display handoff gate installs PMP unless explicitly static. */
#ifdef APPLE_USE_PMP
pmp_dart: iommu@350300000 {
compatible = "apple,t6030-dart", "apple,t8110-dart";
reg = <0x3 0x50300000 0x0 0x4000>;
Expand Down Expand Up @@ -985,6 +987,8 @@
power-domains = <&ps_pmp>, <&ps_pms_sram>;
};

#endif /* APPLE_USE_PMP */

aic: interrupt-controller@351000000 {
compatible = "apple,t6030-aic3", "apple,t8122-aic3";
#interrupt-cells = <3>;
Expand Down
7 changes: 4 additions & 3 deletions arch/arm64/boot/dts/apple/t6031-dcp.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
* interrupts and DART windows are those of the J516C ADT.
*
* Every node stays status = "disabled". The display gate enables the DCP,
* its mailbox, the two DARTs and the display subsystem only when
* apple_t6031_display.enable=1 is on the kernel command line and the boot
* loader has set apple,t6031-handoff = <1>. Compatibles are t6031-specific,
* its mailbox, the two DARTs and the display subsystem only when the boot
* loader has set apple,t6031-handoff = <1> and the native display is
* requested: by default on the J516C, with apple_t6031_display.enable=1 on
* the other boards, never with apple_t6031_display.enable=0. Compatibles are t6031-specific,
* so a kernel that does not know them leaves the nodes unbound.
*
* Only the T6031 board files include this file: t6034.dtsi includes
Expand Down
71 changes: 50 additions & 21 deletions drivers/gpu/drm/apple/apple_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,44 @@ struct apple_drm_private {
};

/* Component readiness is later than platform probe/bind. */
static DEFINE_MUTEX(apple_t6030_display_lock);
static DEFINE_MUTEX(apple_g15_display_lock);
static struct device *apple_t6030_display;
static struct device *apple_t6031_display;

static int apple_t6030_display_publish(struct device *dev)
/* The publication slot of a G15 SoC's internal display subsystem, or NULL. */
static struct device **apple_g15_display_slot(struct device *dev)
{
if (!of_device_is_compatible(dev->of_node, "apple,t6030-display-subsystem"))
if (of_device_is_compatible(dev->of_node, "apple,t6030-display-subsystem"))
return &apple_t6030_display;
if (of_device_is_compatible(dev->of_node, "apple,t6031-display-subsystem"))
return &apple_t6031_display;
return NULL;
}

static int apple_g15_display_publish(struct device *dev)
{
struct device **slot = apple_g15_display_slot(dev);

if (!slot)
return 0;
guard(mutex)(&apple_t6030_display_lock);
if (apple_t6030_display)
return apple_t6030_display == dev ? 0 : -EBUSY;
apple_t6030_display = get_device(dev);
guard(mutex)(&apple_g15_display_lock);
if (*slot)
return *slot == dev ? 0 : -EBUSY;
*slot = get_device(dev);
return 0;
}

static void apple_t6030_display_withdraw(struct device *dev)
static void apple_g15_display_withdraw(struct device *dev)
{
struct device **slot = apple_g15_display_slot(dev);
struct device *old = NULL;

scoped_guard(mutex, &apple_t6030_display_lock) {
if (apple_t6030_display == dev) {
old = apple_t6030_display;
apple_t6030_display = NULL;
if (!slot)
return;
scoped_guard(mutex, &apple_g15_display_lock) {
if (*slot == dev) {
old = *slot;
*slot = NULL;
}
}
put_device(old);
Expand All @@ -96,22 +112,35 @@ static void apple_t6030_display_withdraw(struct device *dev)
* publish separately. This lock protects only publication and a device link;
* no display calls or firmware RPC run while it is held.
*/
int apple_drm_t6030_link_device(struct device *consumer)
static int apple_g15_link_device(struct device *consumer, const char *machine,
const char *gpu, struct device **display)
{
struct device_link *link;

if (!of_machine_is_compatible("apple,t6030") || !consumer->of_node ||
!of_device_is_compatible(consumer->of_node, "apple,agx-t6030"))
if (!of_machine_is_compatible(machine) || !consumer->of_node ||
!of_device_is_compatible(consumer->of_node, gpu))
return -ENODEV;
guard(mutex)(&apple_t6030_display_lock);
if (!apple_t6030_display)
guard(mutex)(&apple_g15_display_lock);
if (!*display)
return -EPROBE_DEFER;
link = device_link_add(consumer, apple_t6030_display,
DL_FLAG_AUTOREMOVE_CONSUMER);
link = device_link_add(consumer, *display, DL_FLAG_AUTOREMOVE_CONSUMER);
return link ? 0 : -EINVAL;
}

int apple_drm_t6030_link_device(struct device *consumer)
{
return apple_g15_link_device(consumer, "apple,t6030", "apple,agx-t6030",
&apple_t6030_display);
}
EXPORT_SYMBOL_GPL(apple_drm_t6030_link_device);

int apple_drm_t6031_link_device(struct device *consumer)
{
return apple_g15_link_device(consumer, "apple,t6031", "apple,agx-t6031",
&apple_t6031_display);
}
EXPORT_SYMBOL_GPL(apple_drm_t6031_link_device);

DEFINE_DRM_GEM_DMA_FOPS(apple_fops);

#define DART_PAGE_SIZE 16384
Expand Down Expand Up @@ -1316,7 +1345,7 @@ static int apple_drm_init(struct device *dev)
drm_client_setup_with_fourcc(&apple->drm, DRM_FORMAT_XRGB8888);

/* A subsequent successful platform probe retries deferred GPU probes. */
ret = apple_t6030_display_publish(dev);
ret = apple_g15_display_publish(dev);
if (ret) {
drm_dev_unregister(&apple->drm);
goto err_unbind;
Expand All @@ -1338,7 +1367,7 @@ static void apple_drm_uninit(struct device *dev)
{
struct apple_drm_private *apple = dev_get_drvdata(dev);

apple_t6030_display_withdraw(dev);
apple_g15_display_withdraw(dev);

/* An aborted takeover leaves its DCPs running until the reboot. */
if (apple->aborted)
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/asahi/asahi_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod queue;
mod regs;
mod slotalloc;
mod stats;
mod stats_raw;
mod sysfs_exports;
mod timestamp;
mod usage;
Expand Down Expand Up @@ -170,7 +171,7 @@ module! {
},
g15_pb_max_blocks: u32 {
default: 3072,
description: "G15: parameter-buffer growth maximum given to the firmware, blocks of 128 KiB (1024..4095 in effect; the blocks above it, up to 4095, answer partial renders; the 512 MiB heap is allocated either way)",
description: "G15: PB growth maximum given to the firmware, 128 KiB blocks (64..4095)",
},
g15_early_tiling: u32 {
default: 0,
Expand Down
90 changes: 88 additions & 2 deletions drivers/gpu/drm/asahi/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ use crate::{
event,
gpu,
mem,
module_parameters, //
module_parameters,
stats_raw::RawStatsSnapshot, //
};
use core::sync::atomic::Ordering;
use kernel::{
c_str,
prelude::*,
sync::Arc,
sync::{
Arc,
SpinLock, //
},
time::{
delay::fsleep,
Delta,
Expand Down Expand Up @@ -588,6 +592,9 @@ pub(crate) struct StatsChannel {
dev: AsahiDevRef,
ch: RxChannel<ChannelState, RawStatsMsg::ver>,
snap: Arc<crate::stats::StatsSnapshot>,
/// Last raw sample of every statistics kind, shared with the export
/// through `crate::stats_raw`.
raw: Arc<SpinLock<RawStatsSnapshot>>,
/// Rate of firmware stats-message timestamps (Hz). All stats timestamps
/// run on the chip base clock (`HwConfig::base_clock_hz`, 24 MHz on every
/// supported SoC), not nanoseconds.
Expand All @@ -604,12 +611,14 @@ impl StatsChannel::ver {
dev: AsahiDevice,
alloc: &mut gpu::KernelAllocators,
snap: Arc<crate::stats::StatsSnapshot>,
raw: Arc<SpinLock<RawStatsSnapshot>>,
ts_hz: u64,
) -> Result<StatsChannel::ver> {
Ok(StatsChannel::ver {
dev: dev.clone(),
ch: RxChannel::<ChannelState, RawStatsMsg::ver>::new(alloc, 0x100)?,
snap,
raw,
ts_hz,
last_util_ts: 0,
})
Expand All @@ -631,6 +640,7 @@ impl StatsChannel::ver {
// accessing the enum view is valid.
let msg = unsafe { msg.msg };
cls_dev_dbg!(StatsCh, self.dev, "Stats: {:?}\n", msg);
self.record_raw(&msg);
if module_parameters::stats_export.value() != 0 {
// Retain the latest values for /sys/class/drm/card*/
// device/agx_stats. Read-only with respect to
Expand Down Expand Up @@ -713,4 +723,80 @@ impl StatsChannel::ver {
}
}
}

/// Record one statistics message in the raw per-device snapshot.
///
/// The firmware words are stored exactly as they arrived: no unit is
/// assumed, nothing is scaled and no metric is derived from them.
fn record_raw(&mut self, msg: &StatsMsg::ver) {
let stamp = crate::stats_raw::monotonic_ns();
let mut snap = self.raw.lock();
snap.note_message();
match msg {
StatsMsg::ver::Power { power, .. } => snap.set_power(power.0, stamp),
StatsMsg::ver::PowerOn { off_time, .. } => snap.set_power_on(off_time.0, stamp),
StatsMsg::ver::PowerOff { on_time, .. } => snap.set_power_off(on_time.0, stamp),
StatsMsg::ver::Utilization {
timestamp,
util1,
util2,
util3,
util4,
} => snap.set_utilization(timestamp.0, [*util1, *util2, *util3, *util4], stamp),
StatsMsg::ver::AvgPower {
active_cs,
unk2,
unk3,
unk4,
avg_power,
} => snap.set_avg_power(active_cs.0, [*unk2, *unk3, *unk4], *avg_power, stamp),
StatsMsg::ver::Temperature {
raw_value,
scale,
tmin,
tmax,
..
} => snap.set_temperature(*raw_value, *scale, *tmin, *tmax, stamp),
StatsMsg::ver::PowerState {
timestamp,
last_busy_ts,
active,
poweroff,
unk1,
pstate,
unk2,
unk3,
} => snap.set_power_state(
timestamp.0,
last_busy_ts.0,
*active,
*poweroff,
*unk1,
*pstate,
*unk2,
*unk3,
stamp,
),
StatsMsg::ver::FwBusy { timestamp, busy } => {
snap.set_fw_busy(timestamp.0, *busy, stamp)
}
StatsMsg::ver::PState {
ps_min,
unk1,
ps_max,
unk2,
..
} => snap.set_pstate(*ps_min, *unk1, *ps_max, *unk2, stamp),
StatsMsg::ver::TempSensor {
sensor_id,
raw_value,
scale,
tmin,
tmax,
..
} => snap.set_temp_sensor(*sensor_id, *raw_value, *scale, *tmin, *tmax, stamp),
// The remaining tags are not decoded by the driver.
_ => {}
}
}
}
8 changes: 8 additions & 0 deletions drivers/gpu/drm/asahi/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,12 +302,20 @@ impl platform::Driver for AsahiPlatformDriver {
gpu.init()?;

let stats = gpu.stats_snapshot();
let debug_stats = gpu.raw_stats_snapshot();
let data = try_pin_init!(AsahiDrmRegistrationData { gpu, resources });

// SAFETY: `reg` is stored in `AsahiPlatformDriverData` and dropped when the driver is
// unbound; it is never forgotten.
let reg = unsafe { drm::Registration::new(pdev.as_ref(), drm, data, 0)? };

// The DRM core created this card's debugfs directory when the device was registered;
// publish the raw firmware statistics in it. drm_dev_unregister() removes the file, and
// waits for its readers, before the registration data that owns the snapshot is dropped.
if let Some(snapshot) = debug_stats.as_ref() {
crate::stats_raw::register(reg.device(), snapshot);
}

// Register the sysfs file on the platform device. Must happen after
// the DRM device is registered so the device is fully bound.
let raw_dev = pdev.as_ref().as_raw();
Expand Down
Loading