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
1 change: 1 addition & 0 deletions drivers/gpu/drm/asahi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ config DRM_ASAHI_G15
depends on DRM_ASAHI
depends on DRM_APPLE=y || (DRM_APPLE=m && DRM_ASAHI=m)
select APPLE_T6030_GPU_PMP_LINK
select APPLE_T6031_GPU_PMP_REPORT
select CRYPTO_LIB_SHA256
select DRM_ASAHI_UAT_ADOPTION
default n
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/asahi/g15/boot.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT

//! Admission and firmware start to READY.
Expand Down Expand Up @@ -75,6 +75,7 @@
pub(crate) fn asahi_g15_display_prepare(dev: *mut core::ffi::c_void) -> core::ffi::c_int;
pub(crate) fn asahi_g15_pmp_get(dev: *mut core::ffi::c_void) -> core::ffi::c_int;
pub(crate) fn asahi_g15_pmp_ready() -> core::ffi::c_int;
pub(crate) fn asahi_g15_pmp_report_t6031(enable: bool) -> core::ffi::c_int;
pub(crate) fn asahi_g15_pmp_put(dev: *mut core::ffi::c_void);
fn asahi_g15_reserved_uat(index: u32, start: u64, size: u64) -> bool;
}
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/asahi/g15/glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/pfn.h>
#include <linux/pm_runtime.h>
#include <linux/soc/apple/pmp.h>
#include <linux/soc/apple/pmp-report.h>
#include <linux/soc/apple/display.h>

void asahi_g15_sha256(const u8 *data, size_t len, u8 *out);
Expand All @@ -37,6 +38,7 @@ int asahi_g15_pmp_prepare(struct device *dev);
int asahi_g15_display_prepare(struct device *dev);
int asahi_g15_pmp_get(struct device *dev);
int asahi_g15_pmp_ready(void);
int asahi_g15_pmp_report_t6031(bool enable);
void asahi_g15_pmp_put(struct device *dev);
bool asahi_g15_reserved_uat(u32 index, u64 start, u64 size);

Expand Down Expand Up @@ -184,6 +186,12 @@ int asahi_g15_pmp_ready(void)
return apple_pmp_t6030_gpu_ready();
}

/* T6031: the AGX request of the PMP report, after the firmware is running. */
int asahi_g15_pmp_report_t6031(bool enable)
{
return apple_pmp_report_t6031_gfx(enable);
}

/*
* Give back the vote of asahi_g15_pmp_get() after a start that failed before
* the firmware was touched. The full M3 stack's J514S bridge has no release:
Expand Down
15 changes: 15 additions & 0 deletions drivers/gpu/drm/asahi/g15/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

//! G15 GPU support (T6030, M3 Pro: J514S, J516S; firmware RTKit 2419, the macOS 14.7-14.8 stub).
Expand Down Expand Up @@ -566,6 +566,21 @@
} = KBox::into_inner(firmware);
return Err(orphan(session, objects, channels, init, events, e));
}
if cfg.platform == hw::Platform::DeviceTree {
// T6031: nothing else sets the PMP's AGX request, and without it memory stays at its
// idle floor. Set it after setup, as T6030 does; a failure keeps the GPU as before.
// SAFETY: The session is retained until reboot, and the request with it.
let ret = unsafe { boot::glue::asahi_g15_pmp_report_t6031(true) };
if ret == 0 {
dev_info!(dev.as_ref(), "G15: PMP AGX request set (memory bandwidth scaling)\n");
} else if ret != ENODEV.to_errno() {
dev_warn!(
dev.as_ref(),
"G15: PMP AGX request failed ({}); memory stays at its idle floor\n",
ret
);
}
}
Ok(firmware)
}
}
Expand Down
52 changes: 52 additions & 0 deletions drivers/pmdomain/apple/pmp-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,58 @@ int apple_pmp_report_set_t6030_gfx(struct device *supplier, bool enable)
}
EXPORT_SYMBOL_GPL(apple_pmp_report_set_t6030_gfx);

/*
* T6031 (M3 Max): the GPU is powered by its PMGR domain alone, with no RTKit
* vote, and nothing sets its PTD request, so PMP ignores the GPU's bandwidth
* demand and memory stays at its idle floor. AGX is the acknowledged
* soc-device ID 14 (record 13) of the J516C table. As on T6030, a request
* made before the firmware runs is acknowledged without enabling bandwidth
* scaling: enabling clears and sets it again. On a failed enable the request
* is cleared, which is how the GPU ran before.
*/
int apple_pmp_report_t6031_gfx(bool enable)
{
struct apple_pmp_report *rep, *found = NULL;
struct device_node *pmp = NULL;
const u8 *table = NULL;
int len = 0, ret = -ENODEV;

if (!IS_ENABLED(CONFIG_APPLE_T6031_GPU_PMP_REPORT) ||
!of_machine_is_compatible("apple,t6031"))
return -ENODEV;

rcu_read_lock();
list_for_each_entry_rcu(rep, &apple_pmp_reports, list) {
if (rep->offsets != &apple_pmp_offsets_t6031)
continue;
if (found)
goto out;
found = rep;
}
if (!found)
goto out;
pmp = of_parse_phandle(found->dev->of_node, "apple,pmp", 0);
if (pmp && of_device_is_compatible(pmp, "apple,t6031-pmp-v2"))
table = of_get_property(pmp, "apple,tunable-soc-device", &len);
if (!apple_pmp_devices_valid(table, len > 0 ? len : 0, BIT_ULL(13), BIT_ULL(13), true) ||
memcmp(table + 13 * PMP_SOC_DEVICE_SIZE + 116, "AGX\0\0\0\0\0", 8)) {
ret = -EINVAL;
} else if (readq(found->base + found->offsets->status) != PMP_REPORT_READY) {
ret = -EAGAIN;
} else {
ret = apple_pmp_report_set_state(found, 13, false, false);
if (!ret && enable)
ret = apple_pmp_report_set_state(found, 13, true, false);
if (ret && enable)
apple_pmp_report_set_state(found, 13, false, false);
}
of_node_put(pmp);
out:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(apple_pmp_report_t6031_gfx);

static int apple_pmp_report_entry_set_state(struct generic_pm_domain *genpd, bool enable)
{
struct apple_pmp_report_entry *ent = genpd_to_apple_pmp_report_entry(genpd);
Expand Down
10 changes: 10 additions & 0 deletions drivers/soc/apple/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ config APPLE_T6030_GPU_PMP_LINK
GPU power commands wait for that supplier's acknowledged display
request through the existing PMP report startup and removal rules.

config APPLE_T6031_GPU_PMP_REPORT
bool
depends on APPLE_PMP_REPORT
default n
help
Set the AGX request of the T6031 (M3 Max) PMP report once the G15
firmware runs. The T6031 GPU is powered by its PMGR domain alone, so
nothing else sets that request, and without it the PMP ignores the
GPU's bandwidth demand: memory stays at its idle floor.

config APPLE_DISPLAY_GATE_KUNIT_TEST
bool "KUnit tests for the Apple display gate" if !KUNIT_ALL_TESTS
depends on KUNIT=y && APPLE_T6030_DISPLAY_GATE
Expand Down
7 changes: 7 additions & 0 deletions include/linux/soc/apple/pmp-report.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ int apple_pmp_report_wait_supplier_ready(struct device *supplier, unsigned int t
/* Caller holds the PMP owner's vote lock and keeps the supplier bound. */
int apple_pmp_report_check_t6030_gfx(struct device *supplier);
int apple_pmp_report_set_t6030_gfx(struct device *supplier, bool enable);
/* After the T6031 G15 firmware is running; the request stays until reboot. */
int apple_pmp_report_t6031_gfx(bool enable);
int apple_pmp_report_wait_ready(struct device_node *entry, unsigned long timeout);
int apple_pmp_report_fast_die_effort(const struct device_node *np,
unsigned int lane, u8 *effort);
Expand All @@ -38,6 +40,11 @@ static inline int apple_pmp_report_set_t6030_gfx(struct device *supplier, bool e
return -ENODEV;
}

static inline int apple_pmp_report_t6031_gfx(bool enable)
{
return -ENODEV;
}

static inline int apple_pmp_report_wait_ready(struct device_node *entry,
unsigned long timeout)
{
Expand Down
Loading