Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions Documentation/devicetree/bindings/gpu/apple,agx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ properties:

operating-points-v2: true

apple,clpc:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Host performance controller (CLPC) that the GPU reports its
submissions to, for the memory controller and fabric floors it
raises for GPU work.

apple,firmware-abi:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 3
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/asahi/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0

obj-$(CONFIG_DRM_ASAHI) += asahi.o
asahi-y := asahi_core.o sysfs.o g17/sync_input.o g17/sync_output.o g17/sync_scope.o g17/trace.o
asahi-y := asahi_core.o sysfs.o g17/sync_input.o g17/sync_output.o g17/sync_scope.o g17/trace.o g17/clpc.o
CFLAGS_g17/trace.o := -I$(src)/g17

asahi-$(CONFIG_DRM_ASAHI_G15) += g15/glue.o
Expand Down
18 changes: 18 additions & 0 deletions drivers/gpu/drm/asahi/g17/clpc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
#include <linux/soc/apple/clpc.h>
#include "clpc.h"

int asahi_clpc_gpu_get(void *dev, struct apple_clpc_gpu **out)
{
return apple_clpc_gpu_get(dev, out);
}

void asahi_clpc_gpu_set_active(struct apple_clpc_gpu *gpu, bool active)
{
apple_clpc_gpu_set_active(gpu, active);
}

void asahi_clpc_gpu_put(struct apple_clpc_gpu *gpu)
{
apple_clpc_gpu_put(gpu);
}
13 changes: 13 additions & 0 deletions drivers/gpu/drm/asahi/g17/clpc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#ifndef _ASAHI_G17_CLPC_H
#define _ASAHI_G17_CLPC_H
#include <linux/types.h>
struct apple_clpc_gpu;
/*
* The CLPC's GPU activity input (include/linux/soc/apple/clpc.h). @dev is the
* GPU's struct device, opaque to Rust, whose bindings cannot name it here.
*/
int asahi_clpc_gpu_get(void *dev, struct apple_clpc_gpu **out);
void asahi_clpc_gpu_set_active(struct apple_clpc_gpu *gpu, bool active);
void asahi_clpc_gpu_put(struct apple_clpc_gpu *gpu);
#endif
5 changes: 4 additions & 1 deletion drivers/gpu/drm/asahi/g17/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! G17 GPU support.
Expand Down Expand Up @@ -647,6 +647,8 @@
secondary.stop();
}
self.primary.stop();
// Only once both processors stop can they no longer consume work.
self.port.set_effort_full(false);
self.pool.stop_after_firmware();
// RTKit destruction releases the mailbox power references. Clear the bridge while
// those references still keep the register block powered.
Expand Down Expand Up @@ -693,6 +695,7 @@

/// Called at actual submission publication, not while a queued job is merely being built.
fn note_submission(&mut self) -> Result {
self.port.note_gpu_activity();
self.effort.submit();
self.apply_effort(power::FULL_EFFORT)
}
Expand Down Expand Up @@ -1332,7 +1335,7 @@
secondary,
primary,
bridge,
port: port::Port::new()?,
port: port::Port::new(power::Demand::new(pdev.as_ref().as_raw())?)?,
seen_submissions: 0,
rings: channel::Rings::new(),
recovery: recovery::State::new(),
Expand Down
12 changes: 11 additions & 1 deletion drivers/gpu/drm/asahi/g17/port.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! Device-wide publication state that physical queues share without the device mutex.
Expand Down Expand Up @@ -105,6 +105,8 @@
compute_announced: [AtomicU64; PRIORITIES],
/// Full firmware effort is applied; cleared before an idle clear rechecks `submissions`.
effort_full: AtomicBool,
/// The CLPC's GPU activity input: told of every submission and effort change.
demand: super::power::Demand,
submissions: AtomicU64,
}

Expand Down Expand Up @@ -142,7 +144,7 @@
}

impl Port {
pub(super) fn new() -> Result<Arc<Self>> {
pub(super) fn new(demand: super::power::Demand) -> Result<Arc<Self>> {
Arc::pin_init(
pin_init!(Self {
views: SetOnce::new(),
Expand All @@ -155,6 +157,7 @@
compute_written: [const { AtomicU64::new(0) }; PRIORITIES],
compute_announced: [const { AtomicU64::new(0) }; PRIORITIES],
effort_full: AtomicBool::new(false),
demand,
submissions: AtomicU64::new(0),
}),
GFP_KERNEL,
Expand Down Expand Up @@ -453,6 +456,7 @@
/// clear sees this submission or this submission sees the flag withdrawn.
pub(super) fn note_submission(&self) -> bool {
self.submissions.fetch_add(1, Ordering::SeqCst);
self.note_gpu_activity();
self.effort_full.load(Ordering::SeqCst)
}

Expand All @@ -462,5 +466,11 @@

pub(super) fn set_effort_full(&self, full: bool) {
self.effort_full.store(full, Ordering::SeqCst);
self.demand.set_active(full);
}

/// Reports a submission, published with or without the device mutex, to the CLPC.
pub(super) fn note_gpu_activity(&self) {
self.demand.set_active(true);
}
}
45 changes: 45 additions & 0 deletions drivers/gpu/drm/asahi/g17/power.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! Work-based firmware performance effort. Idle power gating is managed separately by the
Expand Down Expand Up @@ -233,6 +233,51 @@
result
}

unsafe extern "C" {
fn asahi_clpc_gpu_get(
dev: *mut core::ffi::c_void,
out: *mut *mut core::ffi::c_void,
) -> core::ffi::c_int;
fn asahi_clpc_gpu_set_active(gpu: *mut core::ffi::c_void, active: bool);
fn asahi_clpc_gpu_put(gpu: *mut core::ffi::c_void);
}

/// The GPU activity input of the CLPC that the device tree links the GPU to, if any (see
/// `apple_clpc_gpu_get()`). The input has a lifetime of its own, so it may outlive the CLPC; a
/// device link orders the CLPC before the GPU.
pub(super) struct Demand(*mut core::ffi::c_void);

// SAFETY: the input's own spinlock serializes every access to it; it calls back into nothing.
unsafe impl Send for Demand {}
// SAFETY: shared access only reports activity under that lock, never changes the lifetime.
unsafe impl Sync for Demand {}

impl Demand {
pub(super) fn new(dev: *mut kernel::bindings::device) -> kernel::error::Result<Self> {
let mut out = core::ptr::null_mut();
// SAFETY: `dev` is the live platform device and `out` is writable; on success the C
// side returns an owned reference, or NULL when the device tree names no CLPC.
let ret = unsafe { asahi_clpc_gpu_get(dev.cast(), &mut out) };
if ret < 0 {
Err(kernel::error::Error::from_errno(ret))
} else {
Ok(Self(out))
}
}

pub(super) fn set_active(&self, active: bool) {
// SAFETY: the reference taken in `new` is live; NULL is accepted and ignored.
unsafe { asahi_clpc_gpu_set_active(self.0, active) };
}
}

impl Drop for Demand {
fn drop(&mut self) {
// SAFETY: releases exactly the reference taken in `new`, clearing the input first.
unsafe { asahi_clpc_gpu_put(self.0) };
}
}

#[cfg_attr(not(test), kernel::macros::kunit_tests(asahi_g17_idle_hold))]
mod tests {
use super::*;
Expand Down
Loading
Loading