{"id":1180,"date":"2026-07-07T21:08:06","date_gmt":"2026-07-08T04:08:06","guid":{"rendered":"https:\/\/xn--y9aq2bc.com\/?p=1180"},"modified":"2026-07-07T21:08:06","modified_gmt":"2026-07-08T04:08:06","slug":"find-a-way-to-restrict-gpu-usage-by-a-kernel-feature-component","status":"publish","type":"post","link":"https:\/\/xn--y9aq2bc.com\/?p=1180","title":{"rendered":"Find a way to restrict gpu usage by a kernel feature\/component"},"content":{"rendered":"<div class=\"taxonomy-category wp-block-post-terms\"><span class=\"wp-block-post-terms__prefix\">Category: <\/span><a href=\"https:\/\/xn--y9aq2bc.com\/?cat=223\" rel=\"tag\">LLM Chats<\/a><span class=\"wp-block-post-terms__separator\">\u2192<\/span><a href=\"https:\/\/xn--y9aq2bc.com\/?cat=224\" rel=\"tag\">Technical Solutions<\/a><span class=\"wp-block-post-terms__separator\">\u2192<\/span><a href=\"https:\/\/xn--y9aq2bc.com\/?cat=225\" rel=\"tag\">Technology Activism<\/a><\/div>\n\n\n<p class=\"wp-block-paragraph\">====================<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 1 of 20 &#8211; 7\/1\/2026, 6:06:52 PM:<br>Find a way to restrict gpu usage by a kernel feature\/component<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching for GPU restrictions<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I see that the user is asking about a Linux kernel feature or component to restrict GPU usage. It sounds like they\u2019re looking for a practical solution, so I should clarify what they mean by &#8220;find a way.&#8221; I think it might be useful to consider options like cgroups or DRM leasing. I\u2019ll go ahead and perform a web search to gather the most current information on this topic.<strong>Searching for GPU usage limits<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It seems there isn&#8217;t a kernel feature to directly limit GPU usage with cgroups. Instead, I&#8217;d need to look at the devices cgroup to restrict access rather than usage. I&#8217;m also considering options like DRM or KVM here. I need to mention scheduling and containerization as part of this context. I should pull in relevant citations from search results and refer to the kernel documentation for devices cgroup to provide more clarity.<strong>Considering GPU resource limits<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to provide a clear answer about limiting compute usage for GPUs. It looks like the suggestion is to use devices cgroup or MIG for NVIDIA GPUs, as there isn\u2019t a general kernel feature available for limiting GPU compute usage right now. I could reference ThinLinc\u2019s cgroups, which currently don\u2019t support GPU limits, and mention that a patch has been proposed for future GPU time-sharing. I want to keep this concise and focused!There\u2019s no general in-kernel GPU quota controller you can turn on today. On Linux, cgroups can restrict access to GPU device nodes via the devices controller, but that\u2019s device access, not GPU compute\/time limiting; one kernel discussion even proposed a future GPU controller with memory and runtime accounting because GPU time sharing was still future work.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Practical options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Block\/allow GPU devices<\/strong> with cgroups or systemd device policies.<\/li>\n\n\n\n<li><strong>Partition the GPU in hardware<\/strong> if your cards support it, e.g. <strong>NVIDIA MIG<\/strong>.<\/li>\n\n\n\n<li><strong>Use scheduler\/container tooling<\/strong> to assign specific <code>\/dev\/nvidia*<\/code> devices per job, which is what many clusters do.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can give you the exact setup for <strong>cgroups v2 + systemd<\/strong> or for <strong>NVIDIA MIG<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 2 of 20 &#8211; 7\/1\/2026, 6:12:47 PM:<br>Does firmware talk to or controll the gpu directly in any architecture<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Considering architecture information<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;m thinking about providing an answer related to general architecture. It seems I don&#8217;t necessarily need the web since many real-world facts are timeless, even though some may have changed. But I wonder if using the web could give me the latest insights? Hm, maybe it&#8217;s not necessary for this topic. Regardless, I definitely want to keep my response concise and focused! Let&#8217;s see what I can share about architecture.Yes. In many systems, firmware can directly initialize, configure, power-manage, and sometimes even schedule parts of GPU operation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common cases:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PCs\/laptops:<\/strong> system firmware (UEFI\/BIOS) often sets up the PCIe device, power state, memory mapping, and option ROM\/VBIOS handoff before the OS driver takes over.<\/li>\n\n\n\n<li><strong>Discrete GPUs:<\/strong> the GPU usually has its own <strong>VBIOS\/firmware<\/strong>, which the host firmware may load or validate, and the GPU\u2019s onboard microcontrollers often run firmware that handles power, clocks, security, and some command processing.<\/li>\n\n\n\n<li><strong>Integrated GPUs \/ SoCs:<\/strong> platform firmware can be more involved, since the GPU may share memory, clocks, and power rails with the rest of the chip.<\/li>\n\n\n\n<li><strong>Embedded\/console\/mobile systems:<\/strong> firmware commonly has very direct control over the GPU\u2019s bring-up and power state.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">So the short answer is: <strong>yes, in basically all modern architectures firmware talks to the GPU at least during boot and power management, and sometimes more directly through GPU microcode or embedded controllers.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 3 of 20 &#8211; 7\/1\/2026, 6:15:10 PM:<br>Can u-boot load such things for an rk3399 or rk3588 and would there be a way to extend it into the OS<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching for firmware details<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to find answers about U-Boot loading firmware specifically for rk3399 and rk3588, and how it extends into the operating system. It seems like I should perform a web search to gather the most up-to-date and factual specifics since my current knowledge might not be enough. Let\u2019s see what I can discover about this topic to help clarify things!Yes\u2014on RK3399 and RK3588, U-Boot can load the early boot pieces, and then the OS can take over the rest. For Rockchip boards, U-Boot commonly loads DRAM init code\/TPL-SPL plus BL31 (ARM Trusted Firmware), and on RK3588 it also uses a TPL\/DDR binary before handing off to U-Boot proper.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For GPU-related firmware, the usual pattern is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>U-Boot loads whatever early firmware the boot chain needs.<\/li>\n\n\n\n<li>Linux loads the GPU driver and any GPU firmware blobs from <code>\/lib\/firmware<\/code> after boot.<\/li>\n\n\n\n<li>If you want a custom handoff, you can package blobs into the initramfs or have U-Boot load them into RAM and pass them to Linux via reserved memory \/ DT, but Linux still needs driver support to actually consume them.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">So: <strong>U-Boot can load such things, but it usually doesn\u2019t \u201cdrive the GPU\u201d for the whole system; it mostly boots it and then Linux handles the GPU.<\/strong> For RK3588 specifically, U-Boot can also apply DT fixups that disable or enable GPU\/codec blocks based on SoC state before Linux starts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can sketch a concrete boot flow for <strong>RK3399 + Panfrost<\/strong> or <strong>RK3588 + Mali firmware<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 4 of 20 &#8211; 7\/1\/2026, 6:17:38 PM:<br>Yea and consider a how to incorporate a mechanism to let the OS trigger a gpu lockout on resource overconsumption in gpu memory<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br>Yes \u2014 the clean way is to split it into <strong>boot-time setup<\/strong> and <strong>runtime enforcement<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For RK3399\/RK3588, a workable design looks like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>U-Boot sets up the hardware boundary<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>load the normal boot firmware chain<\/li>\n\n\n\n<li>reserve a small shared memory region for control\/telemetry<\/li>\n\n\n\n<li>mark GPU-related memory as reserved in the DT if needed<\/li>\n\n\n\n<li>pass the GPU on to Linux normally<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Linux owns policy<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the GPU driver tracks per-process or per-cgroup VRAM use<\/li>\n\n\n\n<li>when usage crosses a threshold, the kernel triggers a \u201clockout\u201d event<\/li>\n\n\n\n<li>that event can be implemented in software first, then optionally forwarded to firmware<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Firmware\/enforcer handles hard lockout<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>on trigger, firmware or a secure monitor:\n<ul class=\"wp-block-list\">\n<li>stops new command submission<\/li>\n\n\n\n<li>flushes or resets GPU queues<\/li>\n\n\n\n<li>fences the offending context<\/li>\n\n\n\n<li>optionally cuts clocks\/power or gates the device<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Linux then gets a fault\/notification and can recover or kill the offender<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The key point: <strong>don\u2019t make firmware do accounting<\/strong>. Let Linux do accounting, and let firmware do the hard cutoff.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A practical mechanism would be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Shared memory mailbox<\/strong><\/li>\n\n\n\n<li>Linux writes:\n<ul class=\"wp-block-list\">\n<li>offender ID<\/li>\n\n\n\n<li>current VRAM usage<\/li>\n\n\n\n<li>requested action: <code>warn<\/code>, <code>throttle<\/code>, <code>lockout<\/code>, <code>reset<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>firmware reads it and acts<\/li>\n\n\n\n<li><strong>Secure call \/ SMC<\/strong><\/li>\n\n\n\n<li>Linux calls into BL31\/secure monitor to request GPU quarantine<\/li>\n\n\n\n<li>this is better if you want the lockout to be harder for a compromised userspace process to bypass<\/li>\n\n\n\n<li><strong>IOMMU + context teardown<\/strong><\/li>\n\n\n\n<li>on lockout, revoke DMA mappings for that client<\/li>\n\n\n\n<li>this prevents further VRAM access even if the process keeps running<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For a GPU memory overuse policy, I\u2019d use this escalation:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>soft limit: throttle submission<\/li>\n\n\n\n<li>hard limit: reject new allocations<\/li>\n\n\n\n<li>violation: revoke mappings + kill GPU context<\/li>\n\n\n\n<li>repeated violation: full GPU reset \/ power gate<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want the most robust version, the OS should trigger the lockout, but <strong>the actual enforcement should happen below the normal driver path<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>either in a secure monitor<\/li>\n\n\n\n<li>or in a small always-on firmware component<\/li>\n\n\n\n<li>or via IOMMU invalidation plus device reset<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For Rockchip specifically, the most realistic implementation is usually:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Linux driver tracks usage<\/li>\n\n\n\n<li>a small kernel module or driver hook issues the lockout<\/li>\n\n\n\n<li>reset\/power-gating is done through existing platform control paths<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can sketch a concrete <strong>RK3588 boot + lockout design<\/strong> with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>U-Boot changes<\/li>\n\n\n\n<li>device tree nodes<\/li>\n\n\n\n<li>Linux driver hooks<\/li>\n\n\n\n<li>the message format for the lockout mailbox<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 5 of 20 &#8211; 7\/1\/2026, 6:21:17 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Creating a concrete sketch<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to provide a concrete sketch without relying on the web. It seems real-world facts related to architecture might have shifts, but I should focus on what\u2019s mostly accurate. Since I previously used the web for general info, I didn\u2019t need to include citations, but now that\u2019s not the case. It\u2019s better to draft something based on practical architecture principles to ensure its reliability without needing fresh specifics.Here\u2019s a concrete RK3588-style design.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Boot flow<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>U-Boot<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>boots BL31 + U-Boot as usual<\/li>\n\n\n\n<li>reserves a small \u201cGPU control\u201d shared-memory region<\/li>\n\n\n\n<li>adds DT nodes for:\n<ul class=\"wp-block-list\">\n<li>GPU device<\/li>\n\n\n\n<li>reserved control page<\/li>\n\n\n\n<li>reserved telemetry page<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>optionally marks a carveout for firmware-owned state<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Linux<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GPU driver loads normally<\/li>\n\n\n\n<li>a kernel component tracks GPU memory use per:\n<ul class=\"wp-block-list\">\n<li>process<\/li>\n\n\n\n<li>cgroup<\/li>\n\n\n\n<li>DRM context<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>when a limit is crossed, it triggers a lockout request<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Enforcement path<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>kernel sends a secure call or writes a mailbox message<\/li>\n\n\n\n<li>secure monitor \/ always-on firmware:\n<ul class=\"wp-block-list\">\n<li>invalidates GPU context(s)<\/li>\n\n\n\n<li>revokes IOMMU mappings<\/li>\n\n\n\n<li>stops command submission<\/li>\n\n\n\n<li>optionally resets or power-gates the GPU<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Suggested control model<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use three levels:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>soft limit<\/strong>: throttle submissions<\/li>\n\n\n\n<li><strong>hard limit<\/strong>: deny new allocations<\/li>\n\n\n\n<li><strong>lockout<\/strong>: revoke mappings and reset offending context<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">That gives you graceful behavior before the hammer falls.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Minimal mailbox format<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Shared memory could be something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct gpu_lockout_msg {\n    u32 magic;\n    u32 version;\n    u32 action;      \/\/ 1=warn, 2=throttle, 3=lockout, 4=reset\n    u32 pid;\n    u32 cgroup_id;\n    u64 vram_used;\n    u64 vram_limit;\n    u64 timestamp_ns;\n};<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Firmware or secure monitor reads this and acts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Linux side<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You\u2019d want a kernel hook in one of these places:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DRM driver memory-allocate path<\/li>\n\n\n\n<li>cgroup accounting path<\/li>\n\n\n\n<li>IOMMU mapping path<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Best option: hook <strong>allocation accounting<\/strong> in the GPU driver, because by the time DMA mappings are already live, you\u2019re reacting too late.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enforcement sequence<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When over limit:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>stop accepting new GPU jobs from that context<\/li>\n\n\n\n<li>flush in-flight work<\/li>\n\n\n\n<li>unmap GPU buffers for that context<\/li>\n\n\n\n<li>invalidate IOMMU entries<\/li>\n\n\n\n<li>signal userspace with an error<\/li>\n\n\n\n<li>optionally reset GPU if the context misbehaves again<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">What U-Boot should do<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">U-Boot should not do policy. It should only:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>reserve memory<\/li>\n\n\n\n<li>pass device-tree metadata<\/li>\n\n\n\n<li>ensure the firmware\/secure world knows where the control block is<\/li>\n\n\n\n<li>leave enforcement to Linux + secure monitor<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Best implementation split<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>U-Boot<\/strong>: setup only<\/li>\n\n\n\n<li><strong>Linux driver<\/strong>: accounting + policy<\/li>\n\n\n\n<li><strong>secure monitor\/firmware<\/strong>: hard lockout + reset<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">That keeps it maintainable and hard to bypass.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>device-tree sketch + kernel module skeleton<\/strong> next.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 6 of 20 &#8211; 7\/1\/2026, 6:24:33 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Considering design requirements<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It looks like the user wants an answer that involves code, and it seems I don\u2019t need to access the web for this\u2014it&#8217;s about design architecture, which is more of a general knowledge area. I can answer based on what I already know, rather than searching online. I\u2019ll keep my response concise and focused on the design aspects. Let\u2019s see what I can provide for that!Here\u2019s a minimal sketch.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Device tree additions<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>reserved-memory {\n    #address-cells = &lt;2&gt;;\n    #size-cells = &lt;2&gt;;\n    ranges;\n\n    gpu_ctrl: gpu-ctrl@0 {\n        reg = &lt;0x0 0x3f000000 0x0 0x1000&gt;;\n        no-map;\n    };\n};\n\ngpu-lockout {\n    compatible = \"vendor,gpu-lockout\";\n    memory-region = &lt;&amp;gpu_ctrl&gt;;\n    status = \"okay\";\n};<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Kernel-side flow<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GPU driver keeps per-context VRAM accounting.<\/li>\n\n\n\n<li>When usage exceeds limit, call a lockout helper.<\/li>\n\n\n\n<li>Helper writes the mailbox and triggers an SMC or reset path.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>struct gpu_lockout_msg {\n    u32 magic;\n    u32 version;\n    u32 action;\n    u32 pid;\n    u64 vram_used;\n    u64 vram_limit;\n};\n\nstatic void trigger_gpu_lockout(struct gpu_ctx *ctx, u64 used, u64 limit)\n{\n    struct gpu_lockout_msg *msg = ctrl_page;\n\n    msg-&gt;magic = 0x47504c4b; \/* GPLK *\/\n    msg-&gt;version = 1;\n    msg-&gt;action = 3; \/* lockout *\/\n    msg-&gt;pid = task_pid_nr(current);\n    msg-&gt;vram_used = used;\n    msg-&gt;vram_limit = limit;\n\n    arm_smccc_smc(GPU_LOCKOUT_SMC, virt_to_phys(msg), 0, 0, 0, 0, 0, 0, &amp;res);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Enforcement logic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In firmware or secure monitor:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>validate the request<\/li>\n\n\n\n<li>fence the offending GPU context<\/li>\n\n\n\n<li>revoke IOMMU mappings<\/li>\n\n\n\n<li>stop command submission<\/li>\n\n\n\n<li>optionally reset\/power-gate GPU<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Good kernel hook points<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>drm_gem_object_create()<\/code> \/ buffer allocation path<\/li>\n\n\n\n<li>GPU driver context submit path<\/li>\n\n\n\n<li>cgroup accounting integration if you want policy per container<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Practical recommendation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Start with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>software accounting in Linux<\/strong><\/li>\n\n\n\n<li><strong>SMC-based hard lockout<\/strong><\/li>\n\n\n\n<li><strong>IOMMU revoke + context reset<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s the simplest version that can actually work.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can write:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a <strong>real kernel module skeleton<\/strong><\/li>\n\n\n\n<li>or a <strong>Rockchip-specific implementation plan for RK3588<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 7 of 20 &#8211; 7\/1\/2026, 8:21:39 PM:<br>Kernel module<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Considering code skeleton needs<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to focus on the user&#8217;s request for a kernel module skeleton. The instruction suggests using web search for real-world facts, but this seems like a timeless technical question. Given the context, I shouldn&#8217;t need to search the web for this. I&#8217;ll provide a concise code skeleton while ensuring it\u2019s clear and useful for the user. I want to keep it straightforward and relevant without overcomplicating things.Here\u2019s a minimal kernel-module skeleton for a <strong>GPU lockout notifier<\/strong>. It does the accounting trigger in kernel space, then calls into firmware via SMC.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ gpu_lockout.c\n#include &lt;linux\/module.h&gt;\n#include &lt;linux\/kernel.h&gt;\n#include &lt;linux\/init.h&gt;\n#include &lt;linux\/fs.h&gt;\n#include &lt;linux\/uaccess.h&gt;\n#include &lt;linux\/miscdevice.h&gt;\n#include &lt;linux\/mutex.h&gt;\n#include &lt;linux\/mm.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/arm-smccc.h&gt;\n\n#define GPU_LOCKOUT_SMC  0xC200FF01\n#define MAGIC            0x47504C4B  \/* \"GPLK\" *\/\n\nstruct gpu_lockout_msg {\n    u32 magic;\n    u32 version;\n    u32 action;      \/* 1=warn, 2=throttle, 3=lockout, 4=reset *\/\n    u32 pid;\n    u64 vram_used;\n    u64 vram_limit;\n    u64 reserved&#91;2];\n};\n\nstatic void *ctrl_page;\nstatic DEFINE_MUTEX(lockout_lock);\n\nstatic void gpu_trigger_lockout(u64 used, u64 limit)\n{\n    struct arm_smccc_res res;\n    struct gpu_lockout_msg *msg = ctrl_page;\n\n    if (!msg)\n        return;\n\n    mutex_lock(&amp;lockout_lock);\n\n    msg-&gt;magic = MAGIC;\n    msg-&gt;version = 1;\n    msg-&gt;action = 3;\n    msg-&gt;pid = task_pid_nr(current);\n    msg-&gt;vram_used = used;\n    msg-&gt;vram_limit = limit;\n\n    arm_smccc_smc(GPU_LOCKOUT_SMC,\n                  (u64)virt_to_phys(msg), 0, 0, 0, 0, 0, 0, &amp;res);\n\n    mutex_unlock(&amp;lockout_lock);\n}\n\n\/* Demo sysfs knob to simulate overuse *\/\nstatic ssize_t trigger_store(struct device *dev,\n                             struct device_attribute *attr,\n                             const char *buf, size_t count)\n{\n    u64 used, limit;\n\n    if (sscanf(buf, \"%llu %llu\", &amp;used, &amp;limit) == 2)\n        gpu_trigger_lockout(used, limit);\n\n    return count;\n}\nstatic DEVICE_ATTR_WO(trigger);\n\nstatic struct attribute *gpu_attrs&#91;] = {\n    &amp;dev_attr_trigger.attr,\n    NULL,\n};\nATTRIBUTE_GROUPS(gpu);\n\nstatic struct miscdevice gpu_miscdev = {\n    .minor = MISC_DYNAMIC_MINOR,\n    .name  = \"gpu_lockout\",\n    .groups = gpu_groups,\n};\n\nstatic int __init gpu_lockout_init(void)\n{\n    int ret;\n\n    ctrl_page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);\n    if (!ctrl_page)\n        return -ENOMEM;\n\n    ret = misc_register(&amp;gpu_miscdev);\n    if (ret) {\n        free_page((unsigned long)ctrl_page);\n        return ret;\n    }\n\n    pr_info(\"gpu_lockout: loaded\\n\");\n    return 0;\n}\n\nstatic void __exit gpu_lockout_exit(void)\n{\n    misc_deregister(&amp;gpu_miscdev);\n    if (ctrl_page)\n        free_page((unsigned long)ctrl_page);\n    pr_info(\"gpu_lockout: unloaded\\n\");\n}\n\nmodule_init(gpu_lockout_init);\nmodule_exit(gpu_lockout_exit);\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"you\");\nMODULE_DESCRIPTION(\"GPU lockout notifier\");<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">How to use it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>load the module<\/li>\n\n\n\n<li>write two numbers to <code>\/dev\/gpu_lockout<\/code> via the <code>trigger<\/code> sysfs attribute<\/li>\n\n\n\n<li>it sends an SMC with a lockout request<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"104857600 67108864\" &gt; \/sys\/class\/misc\/gpu_lockout\/trigger<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What\u2019s missing for a real version:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>hook into the actual GPU driver\u2019s allocation path<\/li>\n\n\n\n<li>track per-context or per-cgroup VRAM usage<\/li>\n\n\n\n<li>replace the demo sysfs trigger with real accounting<\/li>\n\n\n\n<li>use a real SMC ID and secure-world handler<\/li>\n\n\n\n<li>add IOMMU revocation \/ context reset logic<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>proper DRM-side hook<\/strong> for Panfrost or a <strong>cgroup-aware version<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 8 of 20 &#8211; 7\/1\/2026, 8:26:29 PM:<br>Cgroup-aware<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching kernel module information<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to provide an answer with a code skeleton, likely related to cgroup-aware kernel modules. Since this involves kernel APIs, it&#8217;s crucial to check for real-world facts that can change over time. While I could draw from my existing knowledge, it seems safer to look up the latest information. I might want to use a related search to ensure I get the most current data relevant to kernel programming.<strong>Considering cgroup modules<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to provide an answer relating to a cgroup-aware kernel module, probably mentioning cgroup v2 and related concepts like class and css. I&#8217;m thinking about including illustrative code, perhaps utilizing task_css for membership, or maybe simpler with task_pgrp. I want to ensure the accuracy of the information. For a real module, I could mention cgroup_subsys_state and css. It\u2019s important to keep it high-level and consider that kernel APIs may differ. I&#8217;ll also need to include citations regarding the cgroup v2 unified hierarchy.Use <strong>cgroup v2<\/strong> and key the GPU quota off the task\u2019s current cgroup; cgroup v2 gives you one unified hierarchy and each process belongs to one cgroup, which makes per-container enforcement much cleaner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A practical module shape is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>userspace creates cgroups<\/strong><\/li>\n\n\n\n<li><strong>your module reads the task\u2019s cgroup<\/strong><\/li>\n\n\n\n<li><strong>you keep VRAM accounting per cgroup<\/strong><\/li>\n\n\n\n<li><strong>on overuse, you lock out that cgroup only<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Minimal skeleton:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;linux\/module.h&gt;\n#include &lt;linux\/kernel.h&gt;\n#include &lt;linux\/fs.h&gt;\n#include &lt;linux\/miscdevice.h&gt;\n#include &lt;linux\/mutex.h&gt;\n#include &lt;linux\/arm-smccc.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/cgroup.h&gt;\n\n#define GPU_LOCKOUT_SMC 0xC200FF01\n#define MAGIC 0x47504C4B\n\nstruct gpu_cg_state {\n    struct cgroup *cg;\n    u64 vram_used;\n    u64 vram_limit;\n    struct list_head node;\n};\n\nstatic LIST_HEAD(states);\nstatic DEFINE_MUTEX(states_lock);\n\nstruct gpu_lockout_msg {\n    u32 magic;\n    u32 version;\n    u32 action;\n    u32 pid;\n    u64 vram_used;\n    u64 vram_limit;\n    u64 cgroup_id;\n};\n\nstatic struct gpu_cg_state *find_or_create_state(struct cgroup *cg)\n{\n    struct gpu_cg_state *s;\n\n    list_for_each_entry(s, &amp;states, node)\n        if (s-&gt;cg == cg)\n            return s;\n\n    s = kzalloc(sizeof(*s), GFP_KERNEL);\n    if (!s)\n        return NULL;\n\n    s-&gt;cg = cg;\n    s-&gt;vram_limit = 256ULL &lt;&lt; 20; \/* example: 256 MiB *\/\n    get_cgroup(cg);\n    list_add(&amp;s-&gt;node, &amp;states);\n    return s;\n}\n\nstatic void gpu_lockout_cgroup(struct cgroup *cg, u64 used, u64 limit)\n{\n    struct arm_smccc_res res;\n    struct gpu_lockout_msg msg = {\n        .magic = MAGIC,\n        .version = 1,\n        .action = 3, \/* lockout *\/\n        .pid = task_pid_nr(current),\n        .vram_used = used,\n        .vram_limit = limit,\n        .cgroup_id = cgroup_id(cg),\n    };\n\n    arm_smccc_smc(GPU_LOCKOUT_SMC,\n              (u64)&amp;msg, 0, 0, 0, 0, 0, 0, &amp;res);\n}\n\nstatic void gpu_account_alloc(u64 bytes)\n{\n    struct cgroup *cg;\n    struct gpu_cg_state *s;\n\n    cg = task_cgroup(current, 0); \/* cgroup v2 unified hierarchy *\/\n    if (!cg)\n        return;\n\n    mutex_lock(&amp;states_lock);\n    s = find_or_create_state(cg);\n    if (s) {\n        s-&gt;vram_used += bytes;\n        if (s-&gt;vram_used &gt; s-&gt;vram_limit)\n            gpu_lockout_cgroup(cg, s-&gt;vram_used, s-&gt;vram_limit);\n    }\n    mutex_unlock(&amp;states_lock);\n\n    css_put(&amp;cg-&gt;self);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important part is where you hook <code>gpu_account_alloc()<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GPU buffer allocation path<\/li>\n\n\n\n<li>GEM object creation path<\/li>\n\n\n\n<li>driver-specific submit\/bo path<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Best enforcement order:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>deny new allocations<\/strong><\/li>\n\n\n\n<li><strong>fence active jobs<\/strong><\/li>\n\n\n\n<li><strong>revoke IOMMU mappings<\/strong><\/li>\n\n\n\n<li><strong>SMC lockout \/ reset<\/strong><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>real DRM\/Panfrost hook example<\/strong> or a <strong>userspace cgroup control script<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 9 of 20 &#8211; 7\/1\/2026, 8:29:48 PM:<br>panfrost hook<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching for actionability<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to gather data through a web search to address real-world kernel specifics. The important thing here is to ensure that the information I provide is actionable while being cautious. I might also want to note the specifics related to Panfrost during my search. It\u2019s a bit complex, but I\u2019ll proceed with a careful and well-informed approach to ensure I get it right for the user!<strong>Crafting concise answers<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to keep my answer concise and include citations. It looks like Panfrost uses GEM objects for lookup, and possibly I could hook in with gpu_usecount. I might also want to note that there isn\u2019t currently an in-kernel cgroup for Panfrost, but there could be future development for memory cgroups. So, crafting practical hook points will be important as I build this response. Let\u2019s make sure to get those citations in there!Best hook for Panfrost is the <strong>BO allocation and submit path<\/strong>, not the job scheduler.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Panfrost\u2019s submit path resolves user handles to GEM BOs, then attaches mappings and bumps a GPU usecount; that makes <code>panfrost_lookup_bos()<\/code> and <code>panfrost_ioctl_create_bo()<\/code> the right places to add per-cgroup accounting and rejection logic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A clean cgroup-aware pattern is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>on BO create\/import: attribute the allocation to <code>task_cgroup(current, 0)<\/code><\/li>\n\n\n\n<li>store <code>cgroup_id(cg)<\/code> in your per-cgroup state<\/li>\n\n\n\n<li>on each allocation: <code>used += size<\/code><\/li>\n\n\n\n<li>if <code>used > limit<\/code>: deny the allocation and\/or trigger lockout<\/li>\n\n\n\n<li>on BO free: decrement the same cgroup\u2019s usage<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For a Panfrost hook, I\u2019d do it like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>static int my_panfrost_bo_create(struct drm_device *dev,\n                                 struct drm_file *file,\n                                 struct drm_panfrost_create_bo *args)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n    struct my_cg_state *s;\n    int ret;\n\n    mutex_lock(&amp;states_lock);\n    s = find_or_create_state(cg);\n    if (!s) {\n        mutex_unlock(&amp;states_lock);\n        css_put(&amp;cg-&gt;self);\n        return -ENOMEM;\n    }\n\n    if (s-&gt;used + args-&gt;size &gt; s-&gt;limit) {\n        mutex_unlock(&amp;states_lock);\n        css_put(&amp;cg-&gt;self);\n        return -EDQUOT; \/* or -ENOMEM *\/\n    }\n\n    s-&gt;used += args-&gt;size;\n    mutex_unlock(&amp;states_lock);\n    css_put(&amp;cg-&gt;self);\n\n    return real_panfrost_create_bo(dev, file, args);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you want the enforcement to be stronger, add a second check in <code>panfrost_ioctl_submit()<\/code> so a cgroup that is already over limit can\u2019t keep submitting jobs after the BO was allocated. Panfrost already keeps per-file and per-context state, and the DRM scheduler gives you the submit queue structure to stop new work cleanly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One important note: for <strong>actual VRAM\/cgroup enforcement<\/strong>, Linux has been moving toward a device-memory cgroup (<code>dev<\/code> memory accounting) for DRM drivers, meant to limit GPU memory by cgroup hierarchy. That\u2019s the direction you\u2019d want to align with instead of inventing a totally separate accounting model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So the short answer is: hook <strong>Panfrost BO create\/import + submit<\/strong>, key it by <strong>cgroup v2<\/strong>, and use that to trigger your lockout path. If you want, I can write the <strong>exact Panfrost patch points<\/strong> next.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 10 of 20 &#8211; 7\/1\/2026, 8:43:06 PM:<br>Dig deeper into the new device-memory cgroup for drm drivers<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br>The new DRM device-memory cgroup work is basically a <strong>GPU\/vRAM charging controller<\/strong>: it adds <code>dev.memory.current<\/code>, <code>dev.memory.max<\/code>, and <code>dev.memory.total<\/code>, plus DRM helpers to charge\/uncharge device memory per cgroup. The design is hierarchical like other cgroup v2 controllers, and the intent is to let GPU drivers enforce per-cgroup vRAM limits.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What matters for a driver is this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Charge on allocation<\/strong><\/li>\n\n\n\n<li><strong>Uncharge on free<\/strong><\/li>\n\n\n\n<li><strong>Enforce at the resource-manager layer<\/strong><\/li>\n\n\n\n<li><strong>Optionally combine with eviction\/reclaim<\/strong><\/li>\n\n\n\n<li><strong>Key by the task\u2019s cgroup in cgroup v2<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For DRM, the hook is not in userspace ioctl policy; it\u2019s in the memory manager. The patchset explicitly adds:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>drmm_cgroup_register_region()<\/code><\/li>\n\n\n\n<li><code>drmcg_try_charge()<\/code><\/li>\n\n\n\n<li><code>drmcg_uncharge()<\/code><br>and wires them into TTM-based drivers like Xe and AMDGPU.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For a Panfrost-like driver, that means the clean path is:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>BO allocation asks the DRM memory layer for pages\/objects<\/li>\n\n\n\n<li>the memory layer charges the current cgroup<\/li>\n\n\n\n<li>if the cgroup exceeds limit, allocation fails<\/li>\n\n\n\n<li>on BO destruction, the charge is released<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The key benefit is that you don\u2019t need a separate custom cgroup accounting scheme in your module; the DRM core is becoming the place where this belongs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One subtle point: this is mainly aimed at <strong>device memory \/ vRAM-style accounting<\/strong>, not general \u201cGPU compute time\u201d or \u201cGPU usage\u201d in the abstract. It\u2019s a memory limit controller first, not a scheduler controller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can next show how to map that to <strong>Panfrost\u2019s BO allocation path<\/strong> with a concrete patch skeleton.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 11 of 20 &#8211; 7\/1\/2026, 8:46:42 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br>For Panfrost, the clean place to plug into a device-memory cgroup is the <strong>BO allocation\/free path<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Where to hook<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Allocate<\/strong>: when a GEM\/BO is created<\/li>\n\n\n\n<li><strong>Free<\/strong>: when the BO is destroyed<\/li>\n\n\n\n<li><strong>Maybe submit path<\/strong>: only as a second guard<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">What the driver should do<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Determine current cgroup<\/li>\n\n\n\n<li>Ask DRM memory controller to charge <code>size<\/code><\/li>\n\n\n\n<li>If charge fails, return <code>-ENOMEM<\/code> or <code>-EDQUOT<\/code><\/li>\n\n\n\n<li>On free, uncharge the same amount<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Skeleton shape<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>static int panfrost_bo_charge(struct panfrost_device *pfdev, size_t size)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n    int ret;\n\n    if (!cg)\n        return 0;\n\n    ret = drmcg_try_charge(pfdev-&gt;drm.dev, cg, size);\n    css_put(&amp;cg-&gt;self);\n\n    return ret;\n}\n\nstatic void panfrost_bo_uncharge(struct panfrost_device *pfdev, size_t size)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n\n    if (!cg)\n        return;\n\n    drmcg_uncharge(pfdev-&gt;drm.dev, cg, size);\n    css_put(&amp;cg-&gt;self);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Allocation flow<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>int panfrost_create_bo(...)\n{\n    int ret;\n\n    ret = panfrost_bo_charge(pfdev, args-&gt;size);\n    if (ret)\n        return ret;\n\n    ret = real_create_bo(...);\n    if (ret)\n        panfrost_bo_uncharge(pfdev, args-&gt;size);\n\n    return ret;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Free path<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>void panfrost_destroy_bo(...)\n{\n    panfrost_bo_uncharge(pfdev, bo-&gt;size);\n    real_destroy_bo(...);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Practical notes<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Charge <strong>exactly once<\/strong> per object.<\/li>\n\n\n\n<li>Track whether an object was charged, so imports\/exported BOs don\u2019t double count.<\/li>\n\n\n\n<li>If a BO is shared across processes, decide whether to charge:<\/li>\n\n\n\n<li>creator\u2019s cgroup only<\/li>\n\n\n\n<li>or the current user\u2019s cgroup on import<\/li>\n\n\n\n<li>For stricter control, also reject submits from cgroups already over limit.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Best design choice<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you\u2019re targeting a newer kernel, don\u2019t build a parallel accounting system unless you must. Use the DRM device-memory cgroup layer for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>limit enforcement<\/li>\n\n\n\n<li>hierarchy<\/li>\n\n\n\n<li>reclaim\/pressure integration<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then keep your custom code only for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Panfrost-specific object bookkeeping<\/li>\n\n\n\n<li>optional lockout\/reset policy<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can write a <strong>more realistic Panfrost patch diff<\/strong> showing the exact files and call sites.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 12 of 20 &#8211; 7\/1\/2026, 8:48:24 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching for patch information<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I think the user is looking for current information, possibly a patch diff. Since I don\u2019t need to use the web for everything, I can provide illustrative examples. However, real-world kernel changes might require a web search to get the most up-to-date details. Also, I need to remember to cite any claims I make. So, I\u2019ll check the panfrost files for relevant patch points.<strong>Considering patch details<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to get an answer with citations and include the patch skeleton. I should be careful because the current API is uncertain, so I\u2019ll provide an illustrative diff. Since the user confirmed with &#8220;Yes&#8221; for the patch diff, I\u2019ll focus on being concise while ensuring the information is clear and useful. I want to make sure I\u2019m covering all necessary details effectively!Yes \u2014 here\u2019s the realistic patch shape for Panfrost.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The relevant uAPI entry point is <code>DRM_IOCTL_PANFROST_CREATE_BO<\/code>; Panfrost creates BOs there, then maps them into the GPU MMU.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) Add dmem charge in BO create<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In <code>drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<\/code>, charge before <code>drm_gem_shmem_create_with_handle()<\/code> or immediately after, and fail the ioctl if the cgroup is over limit.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,\n                    struct drm_file *file)\n{\n    struct drm_panfrost_create_bo *args = data;\n    struct panfrost_device *pfdev = dev-&gt;dev_private;\n    struct cgroup *cg = task_cgroup(current, 0);\n    int ret;\n\n    if (!args-&gt;size || args-&gt;flags)\n        return -EINVAL;\n\n    ret = drmcg_try_charge(&amp;pfdev-&gt;drm, cg, args-&gt;size);\n    css_put(&amp;cg-&gt;self);\n    if (ret)\n        return ret;\n\n    ret = real_create_bo(dev, data, file);\n    if (ret)\n        drmcg_uncharge(&amp;pfdev-&gt;drm, cg, args-&gt;size);\n\n    return ret;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2) Uncharge on BO destruction<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Whatever object destructor Panfrost uses for its GEM BO, uncharge there.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>static void panfrost_gem_free_object(struct drm_gem_object *obj)\n{\n    struct panfrost_gem_object *bo = to_panfrost_bo(obj);\n\n    drmcg_uncharge(bo-&gt;base.dev, bo-&gt;owner_cg, bo-&gt;size);\n    drm_gem_shmem_free_object(obj);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3) Optionally guard submit too<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Panfrost\u2019s submit path resolves BO handles before queueing jobs, so you can reject submission from already-over-limit cgroups as a second line of defense.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4) Let dmem own the policy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The new dmem controller is specifically for charging device memory and enforcing <code>max<\/code> by cgroup hierarchy; recent work also added reclaim support so lowering a max can synchronously reclaim device memory instead of just failing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Best practical split<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>dmem controller<\/strong>: accounting + limit enforcement<\/li>\n\n\n\n<li><strong>Panfrost<\/strong>: hook BO create\/free<\/li>\n\n\n\n<li><strong>optional lockout module<\/strong>: react to <code>-EDQUOT<\/code> or over-limit events and trigger reset\/quarantine<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>more exact file-by-file patch against current Panfrost code<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 13 of 20 &#8211; 7\/1\/2026, 8:49:57 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Looking for sources<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to find an answer that likely requires citations from the web. It seems I don&#8217;t need to use any tools for this. I might want to search for the exact Panfrost code to gather relevant information. Let\u2019s get started on fetching those sources! I want to ensure I&#8217;m providing accurate and trustworthy information for whatever the user is asking about.Yes. The patch direction is now a real <strong>dev cgroup<\/strong> controller for device memory, and DRM drivers are being wired into it through a core registration API rather than ad hoc per-driver accounting. The xe RFC shows the pattern clearly: register the DRM device with the cgroup controller, store per-region metadata, and call <code>drmcg_try_charge()<\/code> on allocation and <code>drmcg_uncharge()<\/code> on free.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Panfrost, that means the patch should land in the <strong>GEM\/BO allocation path<\/strong>, not the submit path:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>charge on <code>DRM_IOCTL_PANFROST_CREATE_BO<\/code><\/li>\n\n\n\n<li>charge on <code>prime_import<\/code> too<\/li>\n\n\n\n<li>uncharge in the BO destructor<\/li>\n\n\n\n<li>optionally reject submits if the cgroup is already over limit<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Panfrost\u2019s create-BO ioctl is the right entry point, and submit just consumes already-created BOs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A realistic patch layout would be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<\/code><\/li>\n\n\n\n<li>add cgroup registration during probe<\/li>\n\n\n\n<li>hook <code>DRM_IOCTL_PANFROST_CREATE_BO<\/code><\/li>\n\n\n\n<li><code>drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<\/code><\/li>\n\n\n\n<li>store the charging cgroup in <code>struct panfrost_gem_object<\/code><\/li>\n\n\n\n<li>uncharge in the free path<\/li>\n\n\n\n<li>maybe <code>panfrost_gem_prime_import*<\/code><\/li>\n\n\n\n<li>charge imported buffers too<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Conceptually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ret = drmcg_try_charge(&amp;pfdev-&gt;drm, current_cg, size);\nif (ret)\n    return ret;\n\nbo = panfrost_gem_create(...);\nif (IS_ERR(bo))\n    drmcg_uncharge(&amp;pfdev-&gt;drm, current_cg, size);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and on destroy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>drmcg_uncharge(&amp;pfdev-&gt;drm, bo-&gt;cg, bo-&gt;size);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The big win is that the dev cgroup layer can also support <strong>reclaim\/eviction policies<\/strong> for device memory, so limits don\u2019t have to be a hard fail-only mechanism.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can write the <strong>actual Panfrost patch diff skeleton<\/strong> for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>probe\/init,<\/li>\n\n\n\n<li>BO create,<\/li>\n\n\n\n<li>BO free,<\/li>\n\n\n\n<li>prime import.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 14 of 20 &#8211; 7\/1\/2026, 8:54:18 PM:<br>All 4<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br>Here\u2019s a concise patch skeleton for all 4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) probe\/init<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* panfrost_drv.c *\/\n\nstatic int panfrost_probe(struct platform_device *pdev)\n{\n    struct drm_device *drm;\n    int ret;\n\n    drm = drm_dev_alloc(&amp;panfrost_drm_driver, &amp;pdev-&gt;dev);\n    if (IS_ERR(drm))\n        return PTR_ERR(drm);\n\n    \/* Register DRM device with device-memory cgroup controller *\/\n    ret = drmcg_register_device(drm);\n    if (ret) {\n        drm_dev_put(drm);\n        return ret;\n    }\n\n    platform_set_drvdata(pdev, drm);\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2) BO create<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* panfrost_gem.c *\/\n\nstruct panfrost_gem_object {\n    struct drm_gem_shmem_object base;\n    struct cgroup *cg;\n    u64 size;\n};\n\nint panfrost_gem_create(struct drm_device *dev, size_t size, ...)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n    struct panfrost_gem_object *bo;\n    int ret;\n\n    ret = drmcg_try_charge(dev, cg, size);\n    css_put(&amp;cg-&gt;self);\n    if (ret)\n        return ret;\n\n    bo = kzalloc(sizeof(*bo), GFP_KERNEL);\n    if (!bo) {\n        drmcg_uncharge(dev, cg, size);\n        return -ENOMEM;\n    }\n\n    bo-&gt;cg = cg;\n    bo-&gt;size = size;\n    \/* create backing object here *\/\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3) BO free<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>static void panfrost_gem_free_object(struct drm_gem_object *obj)\n{\n    struct panfrost_gem_object *bo = to_panfrost_bo(obj);\n\n    if (bo-&gt;cg)\n        drmcg_uncharge(obj-&gt;dev, bo-&gt;cg, bo-&gt;size);\n\n    css_put(&amp;bo-&gt;cg-&gt;self);\n    drm_gem_shmem_free_object(obj);\n    kfree(bo);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4) prime import<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* panfrost_gem_prime.c *\/\n\nstruct drm_gem_object *\npanfrost_gem_prime_import_sg_table(struct drm_device *dev,\n                   struct dma_buf_attachment *attach,\n                   struct sg_table *sgt)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n    struct panfrost_gem_object *bo;\n    u64 size = sgt-&gt;nents * PAGE_SIZE; \/* placeholder *\/\n    int ret;\n\n    ret = drmcg_try_charge(dev, cg, size);\n    css_put(&amp;cg-&gt;self);\n    if (ret)\n        return ERR_PTR(ret);\n\n    bo = panfrost_import_sg_table(dev, attach, sgt);\n    if (IS_ERR(bo)) {\n        drmcg_uncharge(dev, cg, size);\n        return ERR_CAST(bo);\n    }\n\n    bo-&gt;cg = cg;\n    bo-&gt;size = size;\n    return &amp;bo-&gt;base.base;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Notes<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>drmcg_register_device()<\/code>, <code>drmcg_try_charge()<\/code>, and <code>drmcg_uncharge()<\/code> are the intended DRM-cgroup integration points from the new device-memory controller work.<\/li>\n\n\n\n<li>The actual Panfrost file names and helper names may differ slightly by kernel version, but the placement is right: <strong>probe, create, free, import<\/strong>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>more compile-accurate patch against a specific kernel tree<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 15 of 20 &#8211; 7\/1\/2026, 8:55:14 PM:<br>Yes against kernel 7.0-22<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Searching for kernel information<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It seems like I can&#8217;t find exact details about &#8220;kernel 7.0-22,&#8221; and it might be a typo. I think a web search could help since real-world facts and kernel versions may have changed. I should clarify if it&#8217;s related to Ubuntu. I suspect the Linux kernel version could actually be 6.x, not 7.0. I\u2019ll search for the current panfrost source and devmem cgroup to provide the best answer, even if the version is unclear.<strong>Considering kernel version specifics<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I need to provide an answer related to a specific kernel version. I realize I can&#8217;t give the exact patch because the version might be 7.0-22, and that\u2019s not the same as the source tree. I could mention that kernel 7.0 uses the Panfrost GEM UMA helper. I should provide file names and some accurate compile information, but it might not be the exact diff needed. Also, I need to include a citation.Against Linux 7.0, Panfrost is already moving toward <strong>GEM-UMA<\/strong> helpers, and the BO create\/free\/import paths are still the right patch points. The current Panfrost driver uses <code>panfrost_gem_create()<\/code> for BO creation and <code>panfrost_gem_prime_import_sg_table()<\/code> for PRIME import, with <code>panfrost_gem_free_object()<\/code> as the destructor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A compile-accurate direction for 7.0 is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<\/code><\/li>\n\n\n\n<li>hook <code>DRM_IOCTL_PANFROST_CREATE_BO<\/code><\/li>\n\n\n\n<li>register the device with the DRM memory controller during probe<\/li>\n\n\n\n<li><code>drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<\/code><\/li>\n\n\n\n<li>charge in <code>panfrost_gem_create()<\/code><\/li>\n\n\n\n<li>uncharge in <code>panfrost_gem_free_object()<\/code><\/li>\n\n\n\n<li>charge in <code>panfrost_gem_prime_import_sg_table()<\/code><\/li>\n\n\n\n<li><code>drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<\/code><\/li>\n\n\n\n<li>add per-BO cgroup\/charge metadata<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The skeleton should look more like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* panfrost_gem.h *\/\nstruct panfrost_gem_object {\n    struct drm_gem_shmem_object base;\n    struct drm_mm_node node;\n    struct cgroup *cg;\n    u64 size;\n    bool charged;\n};<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* panfrost_gem.c *\/\nstruct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size)\n{\n    struct panfrost_gem_object *obj;\n\n    obj = kzalloc(sizeof(*obj), GFP_KERNEL);\n    if (!obj)\n        return ERR_PTR(-ENOMEM);\n\n    obj-&gt;size = size;\n    return &amp;obj-&gt;base.base;\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>static int panfrost_gem_charge(struct drm_device *dev, struct panfrost_gem_object *bo)\n{\n    struct cgroup *cg = task_cgroup(current, 0);\n    int ret;\n\n    ret = drmcg_try_charge(dev, cg, bo-&gt;size);\n    if (!ret) {\n        bo-&gt;cg = cg;\n        bo-&gt;charged = true;\n    } else {\n        css_put(&amp;cg-&gt;self);\n    }\n    return ret;\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>void panfrost_gem_free_object(struct drm_gem_object *obj)\n{\n    struct panfrost_gem_object *bo = to_panfrost_bo(obj);\n\n    if (bo-&gt;charged)\n        drmcg_uncharge(obj-&gt;dev, bo-&gt;cg, bo-&gt;size);\n\n    if (bo-&gt;cg)\n        css_put(&amp;bo-&gt;cg-&gt;self);\n\n    drm_gem_shmem_free_object(obj);\n    kfree(bo);\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>struct drm_gem_object *\npanfrost_gem_prime_import_sg_table(struct drm_device *dev,\n                   struct dma_buf_attachment *attach,\n                   struct sg_table *sgt)\n{\n    struct drm_gem_object *obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);\n    struct panfrost_gem_object *bo;\n\n    if (IS_ERR(obj))\n        return obj;\n\n    bo = to_panfrost_bo(obj);\n    bo-&gt;size = obj-&gt;size;\n    return obj;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">One important correction: for 7.0, don\u2019t assume old <code>drmcg_*<\/code> names are stable unless your tree already has that API wired in; the device-memory cgroup work is still a moving DRM-core interface, but the design is exactly this: register the DRM device, charge on allocation, uncharge on free, and let the cgroup controller enforce limits.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can write this as a <strong>single patch file<\/strong> with realistic <code>diff --git<\/code> blocks for <code>panfrost_drv.c<\/code>, <code>panfrost_gem.c<\/code>, and <code>panfrost_gem.h<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 16 of 20 &#8211; 7\/1\/2026, 8:56:59 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Considering patch file options<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It seems the user is asking about a patch file. I\u2019m thinking I probably won\u2019t need to use the web for this. I\u2019ll need to provide some sort of sketch or framework for crafting the patch, keeping in mind that there might be uncertainties with the API. It\u2019s important to address those without unnecessarily complicating things. So, I\u2019ll focus on creating a clear and useful response for the user.&#8220;`diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>index 111111111111..222222222222 100644<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>@@ -1,6 +1,7 @@<br>struct panfrost_gem_object {<br>struct drm_gem_shmem_object base;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct cgroup *cg;<br>u64 size;<\/li>\n\n\n\n<li>bool charged;<br>};<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>index 111111111111..222222222222 100644<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>@@ -1,6 +1,7 @@<br>#include<br>#include<br>#include<br>+#include<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int panfrost_probe(struct platform_device *pdev)<br>{<br>@@ -20,6 +21,10 @@ static int panfrost_probe(struct platform_device *pdev)<br>if (ret)<br>goto err_drm_dev_put;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ret = drmcg_register_device(drm);<\/li>\n\n\n\n<li>if (ret)<\/li>\n\n\n\n<li>goto err_drm_dev_put;<br>+<br>platform_set_drvdata(pdev, drm);<br>return 0;<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>index 111111111111..222222222222 100644<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>@@ -1,6 +1,7 @@<br>#include<br>#include<br>#include<br>+#include<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int panfrost_gem_charge(struct drm_device *dev,<br>struct panfrost_gem_object *bo)<br>{<br>struct cgroup *cg;<br>int ret;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> cg = task_cgroup(current, 0);\n if (!cg)\n     return -EINVAL;\n\n ret = drmcg_try_charge(dev, cg, bo-&gt;size);<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>css_put(&amp;cg->self);<br>if (ret)<\/li>\n\n\n\n<li>css_put(&amp;cg->self);<\/li>\n\n\n\n<li>else {<\/li>\n\n\n\n<li>bo->cg = cg;<\/li>\n\n\n\n<li>bo->charged = true;<\/li>\n\n\n\n<li>}<br>+<br>return ret;<br>} static void panfrost_gem_free_object(struct drm_gem_object *obj)<br>{<br>struct panfrost_gem_object *bo = to_panfrost_bo(obj);<\/li>\n\n\n\n<li>if (bo->charged) {<\/li>\n\n\n\n<li>drmcg_uncharge(obj->dev, bo->cg, bo->size);<\/li>\n\n\n\n<li>css_put(&amp;bo->cg->self);<\/li>\n\n\n\n<li>}<br>+<br>drm_gem_shmem_free_object(obj);<br>kfree(bo);<br>} int panfrost_gem_create(struct drm_device *dev, size_t size, \u2026)<br>{<br>struct panfrost_gem_object *bo;<br>int ret; bo = kzalloc(sizeof(*bo), GFP_KERNEL);<br>if (!bo)<br>return -ENOMEM; bo->size = size;<br>ret = panfrost_gem_charge(dev, bo);<br>if (ret) {<br>kfree(bo);<br>return ret;<br>} \/* existing GEM\/shmem backing allocation path *\/<br>ret = drm_gem_shmem_object_init(dev, &amp;bo->base, size);<br>if (ret) {<br>drmcg_uncharge(dev, bo->cg, bo->size);<br>css_put(&amp;bo->cg->self);<br>kfree(bo);<br>return ret;<br>} return 0;<br>} struct drm_gem_object *<br>panfrost_gem_prime_import_sg_table(struct drm_device *dev,<br>struct dma_buf_attachment *attach,<br>struct sg_table *sgt)<br>{<br>struct drm_gem_object *obj;<br>struct panfrost_gem_object *bo;<br>size_t size = sgt->nents * PAGE_SIZE; \/* placeholder for real size *\/<br>int ret; obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);<br>if (IS_ERR(obj))<br>return obj; bo = to_panfrost_bo(obj);<br>bo->size = size; ret = panfrost_gem_charge(dev, bo);<br>if (ret) {<br>drm_gem_object_put(obj);<br>return ERR_PTR(ret);<br>} return obj;<br>}<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>What this patch does:\n- registers the DRM device with the memory controller in probe\n- charges cgroup memory on BO create\/import\n- uncharges on free\n- stores the owning cgroup in the BO\n\nWhat you\u2019d still need to wire up:\n- the real `drmcg_register_device()` API name in your tree\n- the exact Panfrost init function names in your 7.0 source\n- the real import size calculation\n- a submit-time reject path if you want extra enforcement\n\nIf you want, I can turn this into a **tree-accurate version for your exact 7.0 source layout** with the likely function names in each file.\n\n--------------------\n\nUser prompt 17 of 20 - 7\/1\/2026, 8:58:17 PM:\nYes\n\nGPT-5.4 mini:\n**Searching for current facts**\n\nI need to provide an answer, but there seems to be some ambiguity about the version, specifically kernel 7.0-22. It\u2019s tricky since some real-world details have changed. I think it\u2019s best to conduct a web search to get the most accurate and up-to-date information. After that, I can give a concise answer based on what I find. This way, I can ensure I'm providing the user with the best information possible!**Checking kernel details**\n\nI need to provide an accurate version related to kernel 7.0-22, probably for Ubuntu. It seems like for Linux 7.0\/7.0-22, the specific helper names may vary a bit. The DRM memory cgroup API in-tree uses drm_cgroup_try_charge. However, what I found in the search indicates that the exported functions are termed drm_cgroup_try_charge and not drmcg. So, I\u2019ll need to update that detail.For a 7.0 tree, the more accurate shape is: **use the DRM cgroup API around GEM object creation\/import\/free**, not a custom module helper named `drmcg_*`. The cgroup work for DRM exposes `drm_cgroup_try_charge()` \/ uncharge-style hooks and associates GEM objects with a DRM cgroup. &lt;citation src=\"1,2\"&gt;&lt;\/citation&gt;\n\nSo the tree-accurate Panfrost patch should land here:\n\n- `drivers\/gpu\/drm\/panfrost\/panfrost_drv.c`\n  - `panfrost_probe()` \/ device init: register the DRM device with the DRM cgroup layer\n  - `panfrost_ioctl_create_bo()`: charge before creating the BO\n- `drivers\/gpu\/drm\/panfrost\/panfrost_gem.c`\n  - `panfrost_gem_create()`: store cgroup and charge state\n  - `panfrost_gem_free_object()`: uncharge\n  - `panfrost_gem_prime_import_sg_table()`: charge imported BOs too\n- `drivers\/gpu\/drm\/panfrost\/panfrost_gem.h`\n  - add `cg` \/ `charged` fields\n\nA realistic diff skeleton for 7.0 looks like this:<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>@@<br>struct panfrost_gem_object {<br>struct drm_gem_shmem_object base;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct drm_cgroup *cg;<br>u64 size;<\/li>\n\n\n\n<li>bool charged;<br>};<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>@@<br>static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,<br>struct drm_file *file)<br>{<br>struct drm_panfrost_create_bo *args = data;<br>struct panfrost_gem_object *bo;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct drm_cgroup *cg;<br>int ret; if (!args->size || args->flags)<br>return -EINVAL;<\/li>\n\n\n\n<li>cg = drm_file_cgroup(file);<\/li>\n\n\n\n<li>ret = drm_cgroup_try_charge(dev, cg, args->size);<\/li>\n\n\n\n<li>if (ret)<\/li>\n\n\n\n<li>return ret;<br>+<br>bo = panfrost_gem_create(dev, args->size, args->flags);<\/li>\n\n\n\n<li>if (IS_ERR(bo))<\/li>\n\n\n\n<li>return PTR_ERR(bo);<\/li>\n\n\n\n<li>if (IS_ERR(bo)) {<\/li>\n\n\n\n<li>drm_cgroup_uncharge(dev, cg, args->size);<\/li>\n\n\n\n<li>return PTR_ERR(bo);<\/li>\n\n\n\n<li>}<\/li>\n\n\n\n<li>bo->cg = cg;<\/li>\n\n\n\n<li>bo->charged = true; \u2026<br>}<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>@@<br>static void panfrost_gem_free_object(struct drm_gem_object *obj)<br>{<br>struct panfrost_gem_object *bo = to_panfrost_bo(obj);<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>if (bo->charged)<\/li>\n\n\n\n<li>drm_cgroup_uncharge(obj->dev, bo->cg, bo->size);<br>+<br>drm_gem_shmem_free_object(obj);<br>} struct drm_gem_object *<br>panfrost_gem_prime_import_sg_table(struct drm_device *dev,<br>struct dma_buf_attachment *attach,<br>struct sg_table *sgt)<br>{<br>struct drm_gem_object *obj;<br>struct panfrost_gem_object *bo;<\/li>\n\n\n\n<li>struct drm_cgroup *cg;<\/li>\n\n\n\n<li>u64 size = sgt->nents * PAGE_SIZE;<\/li>\n\n\n\n<li>int ret;<\/li>\n\n\n\n<li>cg = drm_file_cgroup(attach->dmabuf->file);<\/li>\n\n\n\n<li>ret = drm_cgroup_try_charge(dev, cg, size);<\/li>\n\n\n\n<li>if (ret)<\/li>\n\n\n\n<li>return ERR_PTR(ret);<br>+<br>obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);<\/li>\n\n\n\n<li>if (IS_ERR(obj))<\/li>\n\n\n\n<li>if (IS_ERR(obj)) {<\/li>\n\n\n\n<li>drm_cgroup_uncharge(dev, cg, size);<br>return obj;<\/li>\n\n\n\n<li>} bo = to_panfrost_bo(obj);<\/li>\n\n\n\n<li>bo->cg = cg;<\/li>\n\n\n\n<li>bo->size = size;<\/li>\n\n\n\n<li>bo->charged = true;<br>return obj;<br>}<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>The exact helper names may differ slightly in your tree, but the integration points are the same: **file cgroup \u2192 charge on BO create\/import \u2192 uncharge on free**. Panfrost\u2019s BO create ioctl is the right hook because submit just consumes already-allocated BOs. &lt;citation src=\"11\"&gt;&lt;\/citation&gt;\n\nIf you want, I can do the next step and rewrite this as a **compile-oriented patch using the actual 7.0 Panfrost function names** from the tree you\u2019re targeting.\n\n--------------------\n\nUser prompt 18 of 20 - 7\/1\/2026, 9:00:05 PM:\nYes\n\nGPT-5.4 mini:\n**Crafting a compile-oriented patch**\n\nThe user wants me to provide a compile-oriented patch, but I\u2019m uncertain about the current source names. I can\u2019t provide exact details without the source tree, but I should give my best effort. Instead of leading with a caveat, I\u2019ll say, \"Here\u2019s a compile-oriented patch shape...\" with placeholders. Since this is based on real-world facts, I don\u2019t need to search the web for more information. I\u2019ll make sure to include citations in the paragraphs as needed.Here\u2019s the compile-oriented version, using the Panfrost BO path and the DRM cgroup charge\/uncharge hooks as the integration point. The DRM cgroup work is meant to charge device memory on allocation and release it on free, so Panfrost should wire into BO create\/import\/destruct rather than submit. &lt;citation src=\"1,2\"&gt;&lt;\/citation&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h<br>@@<br>#include<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">struct panfrost_gem_object {<br>struct drm_gem_shmem_object base;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct drm_cgroup *cg;<br>u64 size;<\/li>\n\n\n\n<li>bool charged;<br>};<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c<br>@@<br>#include<br>+#include<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,<br>struct drm_file *file)<br>{<br>struct drm_panfrost_create_bo *args = data;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct drm_cgroup *cg;<\/li>\n\n\n\n<li>int ret; if (!args->size || args->flags)<br>return -EINVAL;<\/li>\n\n\n\n<li>cg = drm_file_cgroup(file);<\/li>\n\n\n\n<li>ret = drm_cgroup_try_charge(dev, cg, args->size);<\/li>\n\n\n\n<li>if (ret)<\/li>\n\n\n\n<li>return ret;<br>+<br>return panfrost_gem_create_bo(dev, args->size, file);<br>}<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>&#8212; a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>@@<br>#include<br>+#include<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static void panfrost_gem_free_object(struct drm_gem_object *obj)<br>{<br>struct panfrost_gem_object *bo = to_panfrost_bo(obj);<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>if (bo->charged)<\/li>\n\n\n\n<li>drm_cgroup_uncharge(obj->dev, bo->cg, bo->size);<br>+<br>drm_gem_shmem_free_object(obj);<br>} struct drm_gem_object *<br>panfrost_gem_prime_import_sg_table(struct drm_device *dev,<br>struct dma_buf_attachment *attach,<br>struct sg_table *sgt)<br>{<br>struct drm_gem_object *obj;<br>struct panfrost_gem_object *bo;<\/li>\n\n\n\n<li>struct drm_cgroup *cg;<\/li>\n\n\n\n<li>u64 size = PAGE_ALIGN(attach->dmabuf->size);<\/li>\n\n\n\n<li>int ret;<\/li>\n\n\n\n<li>cg = drm_file_cgroup(attach->dmabuf->file);<\/li>\n\n\n\n<li>ret = drm_cgroup_try_charge(dev, cg, size);<\/li>\n\n\n\n<li>if (ret)<\/li>\n\n\n\n<li>return ERR_PTR(ret);<br>+<br>obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);<\/li>\n\n\n\n<li>if (IS_ERR(obj))<\/li>\n\n\n\n<li>if (IS_ERR(obj)) {<\/li>\n\n\n\n<li>drm_cgroup_uncharge(dev, cg, size);<br>return obj;<\/li>\n\n\n\n<li>} bo = to_panfrost_bo(obj);<\/li>\n\n\n\n<li>bo->cg = cg;<\/li>\n\n\n\n<li>bo->size = size;<\/li>\n\n\n\n<li>bo->charged = true;<br>return obj;<br>}<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">diff<br>diff &#8211;git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c<br>@@<br>int panfrost_gem_create_bo(struct drm_device *dev, size_t size,<br>struct drm_file *file)<br>{<br>struct panfrost_gem_object *bo;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>struct drm_cgroup *cg = drm_file_cgroup(file);<br>int ret; bo = kzalloc(sizeof(*bo), GFP_KERNEL);<br>if (!bo)<br>return -ENOMEM; bo->size = size;<\/li>\n\n\n\n<li>bo->cg = cg;<\/li>\n\n\n\n<li>bo->charged = true; ret = drm_gem_shmem_object_init(dev, &amp;bo->base, size);<br>if (ret) {<\/li>\n\n\n\n<li>drm_cgroup_uncharge(dev, cg, size);<br>kfree(bo);<br>return ret;<br>} return 0;<br>}<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>What to adjust in your tree:\n- if your 7.0 headers use slightly different names than `drm_cgroup_*`, keep the same placement and swap to the exact helper names\n- if Panfrost\u2019s create helper is named differently, hook the same logic in the ioctl handler that creates BOs\n- use the real imported-BO size instead of the placeholder `attach-&gt;dmabuf-&gt;size` if your tree exposes a better source\n\nThe important part is the flow: **charge on create\/import, store cgroup in the BO, uncharge on free**. That\u2019s the right place to make GPU memory lockout policy work cleanly with cgroups. &lt;citation src=\"1,11\"&gt;&lt;\/citation&gt;\n\nIf you want, I can do one more pass and turn this into a **single minimal patch series** with:\n1. cgroup header additions,\n2. BO create\/import changes,\n3. free-path uncharge,\n4. optional over-limit lockout return path.\n\n--------------------\n\nUser prompt 19 of 20 - 7\/1\/2026, 9:01:58 PM:\nAll 4\n\nGPT-5.4 mini:\n**Considering concise answers**\n\nI need to be concise since the user has asked all four questions, which likely means I should provide a patch series. I don't think I need to use the web right now, but I have to consider that real-world kernel facts might have changed. \n\nWe've used the web before, and I can aim for the best effort with citations. I need to be careful not to claim exact APIs since that could be uncertain. I'll provide the patch series with a note that helper names may differ, but I want to ensure my answer is direct.```diff\nFrom 0001 Mon Sep 17 00:00:00 2001\nSubject: &#91;PATCH 1\/4] drm\/panfrost: add cgroup charge state to GEM objects\n\ndiff --git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h\n--- a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h\n+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.h\n@@\n struct panfrost_gem_object {\n     struct drm_gem_shmem_object base;\n+    struct cgroup *cg;\n     u64 size;\n+    bool charged;\n };<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>From 0002 Mon Sep 17 00:00:00 2001\nSubject: &#91;PATCH 2\/4] drm\/panfrost: charge BOs on create and import\n\ndiff --git a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c\n--- a\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c\n+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_gem.c\n@@\n #include &lt;linux\/cgroup.h&gt;\n+#include &lt;drm\/drm_cgroup.h&gt;\n\n static int panfrost_gem_charge(struct drm_device *dev,\n                    struct panfrost_gem_object *bo,\n                    struct drm_file *file)\n {\n     struct cgroup *cg;\n     int ret;\n\n     cg = task_cgroup(current, 0);\n     if (!cg)\n         return -EINVAL;\n\n     ret = drm_cgroup_try_charge(dev, cg, bo-&gt;size);\n     if (ret) {\n         css_put(&amp;cg-&gt;self);\n         return ret;\n     }\n\n     bo-&gt;cg = cg;\n     bo-&gt;charged = true;\n     return 0;\n }\n\n static void panfrost_gem_free_object(struct drm_gem_object *obj)\n {\n     struct panfrost_gem_object *bo = to_panfrost_bo(obj);\n\n     if (bo-&gt;charged)\n         drm_cgroup_uncharge(obj-&gt;dev, bo-&gt;cg, bo-&gt;size);\n\n     if (bo-&gt;cg)\n         css_put(&amp;bo-&gt;cg-&gt;self);\n\n     drm_gem_shmem_free_object(obj);\n }\n\n struct drm_gem_object *\n panfrost_gem_prime_import_sg_table(struct drm_device *dev,\n                    struct dma_buf_attachment *attach,\n                    struct sg_table *sgt)\n {\n     struct drm_gem_object *obj;\n     struct panfrost_gem_object *bo;\n     int ret;\n\n     obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);\n     if (IS_ERR(obj))\n         return obj;\n\n     bo = to_panfrost_bo(obj);\n     bo-&gt;size = PAGE_ALIGN(attach-&gt;dmabuf-&gt;size);\n\n     ret = panfrost_gem_charge(dev, bo, attach-&gt;dmabuf-&gt;file);\n     if (ret) {\n         drm_gem_object_put(obj);\n         return ERR_PTR(ret);\n     }\n\n     return obj;\n }<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>From 0003 Mon Sep 17 00:00:00 2001\nSubject: &#91;PATCH 3\/4] drm\/panfrost: charge cgroup in BO create ioctl\n\ndiff --git a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n--- a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n@@\n #include &lt;drm\/drm_drv.h&gt;\n+#include &lt;drm\/drm_cgroup.h&gt;\n\n static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,\n                     struct drm_file *file)\n {\n     struct drm_panfrost_create_bo *args = data;\n     struct panfrost_gem_object *bo;\n+    struct cgroup *cg;\n     int ret;\n\n     if (!args-&gt;size || args-&gt;flags)\n         return -EINVAL;\n\n+    cg = task_cgroup(current, 0);\n+    if (!cg)\n+        return -EINVAL;\n+\n+    ret = drm_cgroup_try_charge(dev, cg, args-&gt;size);\n+    if (ret) {\n+        css_put(&amp;cg-&gt;self);\n+        return ret;\n+    }\n+\n     bo = panfrost_gem_create(dev, args-&gt;size, args-&gt;flags);\n     if (IS_ERR(bo)) {\n+        drm_cgroup_uncharge(dev, cg, args-&gt;size);\n+        css_put(&amp;cg-&gt;self);\n         return PTR_ERR(bo);\n     }\n\n+    bo-&gt;cg = cg;\n+    bo-&gt;size = args-&gt;size;\n+    bo-&gt;charged = true;\n     return 0;\n }<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>From 0004 Mon Sep 17 00:00:00 2001\nSubject: &#91;PATCH 4\/4] drm\/panfrost: reject over-limit cgroups early\n\ndiff --git a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n--- a\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n+++ b\/drivers\/gpu\/drm\/panfrost\/panfrost_drv.c\n@@\n static int panfrost_ioctl_submit(struct drm_device *dev, void *data,\n                  struct drm_file *file)\n {\n+    if (drm_cgroup_is_over_limit(dev, task_cgroup(current, 0)))\n+        return -EDQUOT;\n+\n     return panfrost_submit_job(dev, data, file);\n }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Notes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>This is the right structure: <strong>charge on BO create\/import, uncharge on free, optionally block submit if already over limit<\/strong>. That matches the DRM device-memory cgroup direction for GPU memory accounting.<\/li>\n\n\n\n<li>Helper names like <code>drm_cgroup_try_charge()<\/code> \/ <code>drm_cgroup_uncharge()<\/code> may differ slightly in your tree; keep the same placement even if the exact API needs adjusting.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this next into a <strong>single-file prototype module<\/strong> that hooks Panfrost via kprobes instead of editing the driver directly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">User prompt 20 of 20 &#8211; 7\/1\/2026, 9:03:16 PM:<br>Yes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GPT-5.4 mini:<br><strong>Providing code for kprobes<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It looks like the user is asking about creating a single-file prototype for kprobes and thinks there&#8217;s no need for web searches. Since it involves kernel module code, I can go ahead and provide a concise example without any additional caveats. This will help the user understand how to implement it while staying safe within kernel code boundaries. So, I need to ensure the code is clear and straightforward. Let\u2019s get to it!&#8220;`c<br>\/\/ panfrost_cgroup_hook.c<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">include<\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">include<\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">include<\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">include<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">static int ret_submit;<br>static int ret_create;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int pre_create_bo(struct kprobe *p, struct pt_regs *regs)<br>{<br>pr_info(&#8220;panfrost_cgroup_hook: create_bo hit\\n&#8221;);<br>return 0;<br>}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int pre_submit(struct kprobe *p, struct pt_regs *regs)<br>{<br>struct cgroup *cg = task_cgroup(current, 0);<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (!cg)\n    return 0;\n\n\/* prototype policy *\/\nif (cgroup_is_descendant(cg, NULL)) {\n    pr_info(\"panfrost_cgroup_hook: submit from cgroup %llu\\n\",\n        (unsigned long long)cgroup_id(cg));\n}\n\ncss_put(&amp;cg-&gt;self);\nreturn 0;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static struct kprobe kp_create = {<br>.symbol_name = &#8220;panfrost_ioctl_create_bo&#8221;,<br>.pre_handler = pre_create_bo,<br>};<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static struct kprobe kp_submit = {<br>.symbol_name = &#8220;panfrost_ioctl_submit&#8221;,<br>.pre_handler = pre_submit,<br>};<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static int __init hook_init(void)<br>{<br>int ret;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ret = register_kprobe(&amp;kp_create);\nif (ret)\n    return ret;\n\nret = register_kprobe(&amp;kp_submit);\nif (ret) {\n    unregister_kprobe(&amp;kp_create);\n    return ret;\n}\n\npr_info(\"panfrost_cgroup_hook: loaded\\n\");\nreturn 0;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">static void __exit hook_exit(void)<br>{<br>unregister_kprobe(&amp;kp_submit);<br>unregister_kprobe(&amp;kp_create);<br>pr_info(&#8220;panfrost_cgroup_hook: unloaded\\n&#8221;);<br>}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">module_init(hook_init);<br>module_exit(hook_exit);<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MODULE_LICENSE(&#8220;GPL&#8221;);<br>MODULE_AUTHOR(&#8220;you&#8221;);<br>MODULE_DESCRIPTION(&#8220;Prototype Panfrost cgroup hook via kprobes&#8221;);<br>&#8220;`<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is only a <strong>prototype tracer<\/strong>, not a real enforcer. To make it enforce limits, replace the submit probe with logic that:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>looks up the task\u2019s cgroup,<\/li>\n\n\n\n<li>checks your per-cgroup VRAM accounting,<\/li>\n\n\n\n<li>returns a failure path in the driver itself.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want, I can turn this into a <strong>working kretprobe-based denial prototype<\/strong> next.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>==================== User prompt 1 of 20 &#8211; 7\/1\/2026, 6:06:52 PM:Find a way to restrict gpu usage by a kernel feature\/component GPT-5.4 mini:Searching for GPU restrictions I see that the user is asking about a Linux kernel feature or component to restrict GPU usage. It sounds like they\u2019re looking for a practical solution, so I should &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/xn--y9aq2bc.com\/?p=1180\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Find a way to restrict gpu usage by a kernel feature\/component&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"chat","meta":{"footnotes":""},"categories":[223,224,225],"tags":[],"class_list":["post-1180","post","type-post","status-publish","format-chat","hentry","category-llms","category-technical-solutions","category-technology-activism","post_format-post-format-chat"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/posts\/1180","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1180"}],"version-history":[{"count":1,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/posts\/1180\/revisions"}],"predecessor-version":[{"id":1182,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=\/wp\/v2\/posts\/1180\/revisions\/1182"}],"wp:attachment":[{"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1180"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1180"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xn--y9aq2bc.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1180"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}