Repository navigation
Conversation
…are-metal GPU tables Add the M5 Pro/Max configuration (T6050) and its OF match, selected by the ID registers. A G17 configuration now names its firmware protocol, and the 26A428/25G83 graph tables become optional, since the M5 graph carries its own. Probe refuses an M5 board that has no bare-metal GPU page tables, and the M5 boot entry point stays closed until one does. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..15e1b3e4fa44 (3 commits); SPTM/APIF removed; adapted to integration's g17::Config, ProbeConfig and Firmware::Identified; original 6613f5ab7b7e, 1a021061f226, 15e1b3e4fa44 ] [ rebased onto integration/aurora 33bec40: conflicts in driver.rs and hw/mod.rs only; the M5 Pro/Max/Ultra probe entry and function are named ProbeConfig::G17M5 and probe_g17_m5 beside integration's T8142 backend (ProbeConfig::M5, probe_m5); hw::t6050 sits beside hw::t8152 ] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…d context pins Add the UAT pieces the M5 queues use: sparse-tile binds and their zeroed and per-VM sink tiles, render pool mappings that move with a pool identity, the metrics alias, execution-context pins and the M5 dynamic kernel ranges. On M5, a healthy last-job release skips the VM drain. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..692d42fb35d7 (5 commits); SPTM/APIF removed; adapted to integration's mmu.rs (7.3 GPUVM, UatQuirks, ExecutionRoot, SG leases); comments and names reworded; M5 paths restored where the first rewrite lost them: one prepare_bind_object, with the sparse-tile bind; the G15/G16 adopted UAT (Uat::new_adopted_inner) sets m5: false, for integration's own config (defconfig + asahi.config), which builds G16 beside G17 and failed with E0063 without it; original 6613f5ab7b7e, e25ba8a6fb2b, 1a021061f226, f49e91b3f364, 692d42fb35d7 ] [ rebased onto integration/aurora 33bec40: conflicts in mmu.rs only; the sparse_tile and table modules sit beside integration's t8152 one, and the sparse-tile map path follows integration's no-peer map preflight ] [jq: dropped the per-VM metrics alias cache; each render now maps only its own metrics entry, per review] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Add the M5 firmware's InitData layout and its graph builder, and let InitData address the M5 bundle, private state, recovery views, effort word and control ring at their M5 locations. Firmware events stay off on M5 until its queues take submission, and the M5 effort word is published as zero. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..77dc6eb34210 (5 commits); SPTM/APIF removed; adapted to integration's InitData (status_b and views fields) and fw::Variant; comments and names reworded; M5 paths restored where the first rewrite lost them: the M5 metrics binding; original 6613f5ab7b7e, e25ba8a6fb2b, 1a021061f226, f49e91b3f364, 77dc6eb34210 ] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…-list layout Add the M5 pool descriptor and free-list encodings, the render storage demand they are sized from, and M5 render and compute pools beside the existing ones. Render pool identities become leases that can move between logical contexts, so idle storage is reused instead of rebuilt. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..77dc6eb34210 (4 commits); SPTM/APIF removed; adapted to integration's freelist (capacity refusals, lower-window placement, per-context render pools); comments and names reworded; original 6613f5ab7b7e, e25ba8a6fb2b, cda233bc91f7, 77dc6eb34210 ] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…mand port Add the M5 queue records, configurations and notifications, and the host command port that installs a queue pair and submits work. On M5, tiling, fragment and compute share the compute ring of each priority, whose outer credits are claimed before either host port is written, all under the device mutex. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..f49e91b3f364 (4 commits); SPTM/APIF removed; adapted to integration's InitData work publication and resource wait domains; comments and names reworded; M5 paths restored where the first rewrite lost them: the UAT's range for the compute kick rings and timestamps, the M5 control records, reports and statistics mask, the M5 firmware preparation, the fault window read, and the scheduler page from the retention pool; original 6613f5ab7b7e, e25ba8a6fb2b, 1a021061f226, f49e91b3f364 ] [ rebased onto integration/aurora 33bec40: conflicts in channel.rs and reports.rs only; Reports::record() takes the family's tag mask beside integration's admitted flag, and the statistics drain keeps integration's per-drain receive time and cutoff ] [jq: test-only; the report tests pass record()'s tag mask and index the second role at TAGS, so KUnit builds at this commit] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…fuses tags past 63 M5's statistics mask adds tag 32 to the G17 family's, and record() keeps 64 tags per role. The report tests checked neither, so a tag counted under the wrong family's mask, or one past 63 indexing beyond its role's samples, would have gone unnoticed. A new case checks that tag 32 counts under M5's mask and not under G17's, and that a tag past 63 is refused even with every mask bit set. The invalid-tag case also tries tags 63 and 64. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Add the render and compute program resources, the shader-write, stage-prefix and whole-attachment render flags, matrix and no-query compute, and their feature bits. The command parser takes the resource commands and the stage-prefix tail; validation applies the M5 command set only where the firmware variant has it. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..a507978ff411 (7 commits); SPTM/APIF removed; adapted to integration's UAPI numbering, ray-query stages and fw::Variant; the M5 UAPI flags and features in the UAPI header with agx3c Mesa's numbers, the stage-prefix fields appended to drm_asahi_cmd_render; interim forms until the render submission commit; comments and names reworded; M5 paths restored where the first rewrite lost them: VM_BIND accepts DRM_ASAHI_BIND_SPARSE_TILE; original 6613f5ab7b7e, e25ba8a6fb2b, bd4a3d7a0c97, 2f58522abec7, 2c5c77b6aaba, e393a52c7151, a507978ff411 ] [ rebased onto integration/aurora 33bec40: conflicts in asahi_drm.h with integration's G18 UAPI; the M5 feature bit 30 and the render (21, 23, 24) and compute (16, 17) flags sit beside integration's G18 definitions, after its notes reserving them, and the bit-30 note names the defined bit; the stage-prefix fields are their own struct drm_asahi_render_stage_prefixes after the 448-byte struct drm_asahi_cmd_render (struct drm_asahi_cmd_render_m5, the same 480 bytes on the wire), as G18 carries its resources, so G18's 448/528-byte payloads and G15's size assert stay as integration has them; command.rs reads that tail ] [jq: GET_PARAMS no longer reports BOUNDED_AS_BUILD on M5, whose command set refuses the flag; the scs_layout doc names M5, per review] [jq: compute and render long-job allowance also counts M5's intersection tables, per review] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…he M5 render payload and resource commands The G17 parser now reads a render with DRM_ASAHI_RENDER_STAGE_PREFIXES as struct drm_asahi_cmd_render_m5, and keeps the M5 render and compute program lists (SET_RENDER_RESOURCES, _V2, SET_COMPUTE_RESOURCES) for the commands after them. The frozen M4 bindings predate those UAPI additions, so declare them beside the flat bindings, check their layout and values against the kernel header as the frozen ones are, and extract the stage-prefix offset and render payload reader with the parser. The program lists are stand-ins that keep their bytes, like the other extension validators. Two cases cover the stage-prefix rules and the resource lists' scope and barriers. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Encode the M5 compute program and descriptor, install M5 compute queues cold and refresh their priority on reuse, and publish compute as M5 work on the shared ring. Timestamps come from the queue's own record, waits on other queues stay in firmware, and the classic compute paths are never taken on M5. A closed context's hung M5 compute is killed through its queue's exit, and the kill settles once the full-queue retirement witness covers the killed commands. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..e393a52c7151 (7 commits); SPTM/APIF removed; adapted to integration's compute queue (cached graph, descriptor ring), completions and runtime; interim forms until the render submission commit; comments and names reworded; M5 paths restored where the first rewrite lost them: the firmware's own compute queue record, the shared compute aperture and global state left to G17P, every compute doorbell in the submission history, the M5 compute pool format, the kill of a closed context's hung compute settled by the full-queue witness, the full CPU refill floor on M5 with the feed's guard against unexecuted intervals and only exact compute execution records feeding it, and the item ring's count and cursor checks before its room is computed; M5 compute capacity threaded through integration's admission (rebind, readiness, growth, rearm); original 6613f5ab7b7e, e25ba8a6fb2b, f49e91b3f364, 7c95830ea3a1, 77dc6eb34210, ee68abb10520, e393a52c7151 ] [jq: M5 refuses a sampler heap at validation, EOPNOTSUPP from SUBMIT, instead of failing the accepted command with ENOTSUPP, per review] [jq: dropped Context::metrics_client; a render now maps only its own metrics entry, per review] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…er with the M5 compute capacity The ioctl-time compute check now takes the validated command and sizes it with Backend::compute_capacity(), which gives G17P its block count and M5 its pool plan; the physical ensure_compute() takes that capacity and an admission. Build compute_capacity() from the production source beside admission_open() and the Api method, keep the four-client reverse-order control, the invalid sizing and the logical-close loop, and add the M5 plan path. The eager-admission control now admits the computed capacity in the callback. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…now that M5 skips the shared compute aperture shared_compute() now returns at once for an M5 context, whose compute queues need no G17P shared aperture. Give the fixture's context is_m5(), keep the eight G17P wait, cancellation and cleanup cases on a G17P context, and add the M5 case: no wait, build or install. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Add the M5 tiling and fragment command encodings, their register programs and kick assembly, the M5 block geometry and buffer layout, and the per-generation render state views. Nothing submits them yet. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..77dc6eb34210 (6 commits); SPTM/APIF removed; adapted to integration's fw::render arguments and register programs; interim forms until the render submission commit; comments and names reworded; original 6613f5ab7b7e, 3d2524b7e48a, e25ba8a6fb2b, 5a71513221de, bd4a3d7a0c97, 77dc6eb34210 ] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Build, park and reuse M5 render pairs and submit renders through them on the device-mutex path, renewing the parameter-buffer token when its binding changes. Attachment conflicts across pairs are ordered in firmware, and unrelated whole-attachment renders are not ordered. [ rebased onto integration/aurora: rewritten from t6050-gpu 6613f5ab7b7e..c3505169be1b (11 commits); SPTM/APIF removed; adapted to integration's render queue, buffer manager and device-mutex render path; the M5 features reported in GET_PARAMS except no query access; comments and names reworded; the no-query-access feature defined but not reported, as in the tested reference; M5 paths restored where the first rewrite lost them: a context's render channel moved to a new pair once its publications retire, and the replay of compute a render consumes, held until the owner's renders park; original 6613f5ab7b7e, e25ba8a6fb2b, 1d74fda93777, cda233bc91f7, 3cfa33f3237f, 77dc6eb34210, b0fdab9e3b55, 2f58522abec7, 2c5c77b6aaba, a507978ff411, c3505169be1b ] [jq: the M5 render layout and pass check run at SUBMIT, so unsupported depth/MSAA passes fail there with EOPNOTSUPP, not after acceptance, per review] [jq: each M5 metrics entry gets its own pages and each render maps only its own entry into its VM, instead of every VM mapping the whole backing read-write, per review] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…s NeoGeneration name The M5 render pairs put the G17P generation and the M5 one behind a Generation enum, and the G17P type became NeoGeneration. Extract NeoGeneration's structure, constructor and addresses (the --old control still reads the old revision's Generation), so the harness keeps testing the same G17P construction and auxiliary address. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…ged renders On M5, Mesa that already sends staged renders under DRM_ASAHI_FEATURE_RENDER_STAGE_PREFIXES sends them in a 368-byte form. This kernel accepts a staged render only as the full 480-byte struct drm_asahi_cmd_render_m5, so the first such render failed with EINVAL and the application lost its device. That Mesa now leaves staged renders off and keeps working; Mesa that sends the full command finds them under a new bit. The kernel reports the full-command form as DRM_ASAHI_FEATURE_RENDER_STAGE_PREFIXES_V2 (bit 33) and no longer reports bit 25, which stays defined for the shorter form. Bits 31 and 32 belong to the G18 backend, so bit 33 is defined after the feature enum, as bit 32 is, and the enum keeps its 32-bit type. What the kernel accepts under DRM_ASAHI_RENDER_STAGE_PREFIXES is unchanged. Bits 24 and 25 must never be reported again: Mesa that knows them sends staged renders of 352 or 368 bytes whose prefix fields lie at bytes 336 to 367, where this kernel's render command carries its ray-query stages. The header says so, and a build-time check keeps both bits out of the M5 feature set. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Add a host GPU power-budget governor for M5 (asahi.m5_thermal_governor, off by default). It holds the SoC hotspot near a target by lowering the budget the firmware reads, shares the heat with a CPU frequency ceiling, and ramps the fans with the hotspot under load. Publishers note GPU activity with or without the device mutex. [ rebased onto integration/aurora: rewritten from t6050-gpu 77dc6eb34210..60a4dd529842 (6 commits); SPTM/APIF removed; adapted to integration's Shared work items and the port's CLPC demand; comments and names reworded; original 77dc6eb34210, 0a75aae77faf, 284638c2a784, cc2c9850d389, f5de511cb487, 60a4dd529842 ] Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
drm_sched_fini cancels each job left on the pending list through cancel_job and frees it right after, while the job's completion callback is still registered on the scheduler fence; cancel_job must signal that fence. When the queue could not settle the packet in time (a busy or failed runtime, or a settle racing another queue's timeout handling), cancel returned with the fence unsignalled. A later settle then ran the freed job's callback: drm_sched_job_done on a job with no s_fence, or a NULL callback once the memory was reused, both seen as oopses in drm_sched_job_timedout under 12-process synchronization CTS. Fail such a completion while its queue still owns it (the VM stays pinned until the queue retires it) and wait briefly for a signaller that already claimed it. Signed-off-by: Diljit Singh <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The M5 Max shares the T6050 SoC and the gpu,t6050 binding with the M5
Pro, but its GPU has four clusters of ten cores instead of two, all eight
AMCCs enabled instead of four, and its own voltage tables.
Move the board-specific HW data behind M5Board { J714, J716c } and pass
the board from the Config to the HW data and initdata builders:
- Performance states carry a core and an SRAM voltage per table. HW perf
lane n carries table n and lanes past the board's table count carry
table 0, which reproduces the J714 data exactly. J716c has four tables
(0 == 3, 1 == 2); they, the auxiliary-domain table and the
relative-frequency curve come from its ADT.
- Cluster count 2 / 4, core count 20 / 40 and core type 0x18 / 0x19
(the core type follows the ID variant).
- The minimum parameter-buffer size: 2 MiB / 3 MiB.
- The register map. J716c maps all eight AMCC windows in slot 3 (MCC
reg[14..21]), and four instances, one per cluster, in slots
20 and 24, where J714 has two at the same stride. Slot 44 is a fixed
pair on both.
Gpu::new() checks the board's cluster and core counts against the GPU's.
Only J714 is probed; the following commits complete the J716c data and
the last one probes it.
The J714 data is unchanged by construction; not retested on J714.
Signed-off-by: Erik Bourget <erik@ebourget.net>
[ J775D: backport onto integration/aurora: adapted to integration's g17::Config (the board check in Gpu::new, the board field of the T6040 and T6041 configurations) and InitData::build_m5; the SPTM boot path's board argument removed; comments reworded for publication (code unchanged by it), and message lines that named register offsets; original fbbb15c50bee ]
Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The three AON PTD records (RT0g, RT1g, RT0r) carry device-specific table indices. Encode them per board; the M5 Max rows are 0x58, 0xa3 and 0xb8. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora; original c280d3b1777e ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Both boards bind gpu,t6050 and probe used the J714 configuration unconditionally, so a Max was rejected at the identity check (ID_VERSION variant 4 instead of 3). Add the J716c Config (variant 4, GpuVariant::C, M5Board::J716c) with its crash-log buffers at the ADT gfx-data-shared-ro-base and gfx1-data-shared-ro-base, and select the configuration from the ID registers after powering AFR, with the same Resources the GPU then boots with. probe_g17() now takes those Resources from its caller; on the other G17 path they are created before the DMA mask is set instead of after. On J714 the only change is that AFR is powered and the ID read once more during probe; both are idempotent. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora: adapted to integration's probe_m5, probe_g17 and Config; the SPTM profile and the SPTM probe with its AFR power-up removed, so J716c, like J714, is refused at probe until it has bare-metal GPU tables; original 11a9c30bacae ] [ rebased onto integration/aurora 33bec40: conflicts in driver.rs only; probe_m5 is probe_g17_m5 (ProbeConfig::G17M5) beside integration's T8142 backend, whose probe arms are unchanged ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The M5 Max uses 8 MiB render blocks and an 8 GiB private-memory address inventory, twice the M5 Pro's 4 MiB and 4 GiB. With the M5 Pro geometry, compute work on the Max ends in firmware recoveries within seconds. Select the render pool from the board at probe, before any pool is built, and size render and compute pool geometry and budgets with it. The M5 Pro values are unchanged. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora: adapted to integration's compute_m5 and PoolGeometry; comments reworded for publication (code unchanged by it), and one word of the message; original 8d4eed54d540 ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The last segment-control word of an M5 render is the part's minimum parameter-buffer size in 32 KiB pages. It was passed the segment count (64), which is right only on the M5 Pro. Derive it from the physical cluster count instead, for every render including single-group ones: 64 pages on the M5 Pro (unchanged) and 96 on the M5 Max. A compile-time check ties the page count to each board's HW data. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora: adapted to integration's queue/render/m5_render_submission.rs; the m5_render_resources.rs hunk dropped, as integration has no such file; comments reworded for publication (code unchanged by it), and message lines that named register offsets; original d290b4a2ceab ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…k on After a compute timeout, the driver asks the firmware to kill the closed context's remaining commands and, once the kill is acknowledged and every command settled, returns the queue to service with fresh backing. On M5 the next owner's first command on that queue then never runs: it retires with a zero-duration record and nothing written, and that client sees a lost device. Commands after it run normally. A killed QID stays killed in the firmware until a queue configuration with its QoS update set binds it to a scheduler page other than the one the firmware has for it. The new owner's first publication carries such a configuration, but its command reaches the still-killed queue first. On M5, reset a killed queue's install state, so the next owner's first publication sends the configuration alone and waits until the firmware consumed it before any command is published. The install record now goes at the ring's current producer: a reinstalled queue restarts at the firmware's consumer, not at zero, where the append was refused. Other GPUs retire a killed queue instead: it keeps its QID and installed graph but takes no owner again, and its backing and exited binding are still freed. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora: M5 half only: the retirement of killed queues on other GPUs and the reinstall and retirement logs removed; adapted to integration's recycle_killed; original 457ef7786341 ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On M5 the recovery path reads no firmware fault reason, so a blamed compute command whose completion record shows zero duration is taken to have never executed: its blame is withdrawn and the command is replayed. But firmware writes exactly that record when it cancels a command that was running, which is what happens when that command faulted. The replay then faults again on the next kick. Read the GPU MMU fault status at every M5 recovery. When it holds a valid fault, report the recovery as a page fault, as the other G17 profile does from the firmware's reason word, so attribution keeps the firmware's blame and the command is not withdrawn. Also log the decoded fault: access, reason, address, page-table level, requestor and VM slot. Signed-off-by: Erik Bourget <erik@ebourget.net> [ J775D: backport onto integration/aurora: adapted to integration's Backend::fault_sources, where InitData::is_m5 already exists; the classify hunk dropped, as integration does not withdraw a blamed compute command; the recovery log prefix changed to the series' "asahi:"; original 6b85752ad673 ] Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
No change for any GPU that runs today: the T6040, T6041 and J713 builds keep their digests. It lets a later commit identify the M5 Ultra's (J775D) GPU firmware, whose loaded image holds two roles plus ranges the boot loader rewrites on every boot. fwid admits a GPU firmware build by the SHA-256 of its loaded TEXT with the 8 entropy bytes of its two entropy records zeroed. That assumes one firmware role per TEXT region and nothing else the boot loader changes. Neither holds for every SoC: the boot loader can load two GPU roles' TEXT back to back into one region, each with its own pair of entropy records, and fill other ranges of it on every boot (two RTKit sections it patches and two load fields of each image header). A build now lists its entropy records per role (at most two roles) and the (offset, length) ranges the boot loader fills. Both are zeroed in a private copy before hashing, so a loaded image and the firmware file it came from hash alike. A build with no boot-filled ranges is hashed as before, in place, with only its entropy zeroed: every existing build keeps its digest. A record counts only if it is whole (its tag, length and 8 entropy bytes all inside TEXT), in both paths and when an unknown image's records are located, so a tag in the last 8 bytes of an unknown image is refused like any other unknown image instead of indexing past the end. measure() copies the loaded TEXT twice, before anything is written to the GPU, and keeps the copy only if both agree; Measured::find() looks a build's images up in that one measurement, and Measured::identity() states an unknown image in the form a pinned build would take (sizes, each role's records, the number of boot-filled ranges zeroed, the digest). identify() is built on them. Testing: the fwid unit tests cover two roles, boot-filled ranges, malformed records and ranges (each leaving the image unchanged) and a record without its entropy bytes, in a pinned build's lookup and in an unknown image's report. They pass on the host: fwid.rs built by rustc --test against a stand-in for the kernel crate (KUnit itself was not run). Without the whole-record check the new test panics on the slice. The existing builds (T6040, T6041 and J713) name their one pair of records and no boot-filled ranges, and keep their digests. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…oard No change in what is written for J714 or J716c. The per-board values move into a table so the M5 Ultra (J775D), which runs the same firmware build with other values, can be added as a third board. M5Board picks each per-board value of the M5 graph by a match on the board: performance and auxiliary-domain states, core count and revision, AON records, register windows, render pool and minimum parameter buffer. The policy controller configuration and the leakage calibration it was made for stay outside it. A third T6050 board runs the same firmware build with other values of each, more voltage tables than a performance state holds and a second auxiliary lane. Collect the values in fw::m5::initdata::Board, a table per board (J714 and J716C, with M5Board's values), and name a configuration's board in Config::m5 in place of Config::m5_board. The builder, the HW data and AON encoders, the render pool selection, the board check and the maximum frequency read the table, and the table carries the controller configuration and its calibration. A performance state holds up to eight voltage tables and an auxiliary state two lanes; a board names how many tables it uses, and lanes past them carry table 0, as before. J716C keeps J714's controller configuration and calibration, so, as before, the configuration applies only to a part with J714's calibration. No change in what is written for J714 or J716c. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On the M5 Ultra Mac Studio (J775D) the GPU driver found no configuration
for the chip ("No M5 configuration for GPU variant") and the GPU stayed
off. It now boots both GPU firmware roles on bare metal and brings up
the M5 firmware graph; jobs are accepted from the later submission
commit on.
J775D (T6050, G17D, two dies) runs the M5 firmware's protocol with the
UAT roots both roles publish (FirmwareProfile::M5PublishedRoots).
- The J775D board: both dies' register windows with their explicit
instances (32), one voltage table per cluster in the main
performance table, the two-lane auxiliary table, the six Ultra AON
records, core type 0x1a revision 2, 8 clusters of 10 cores and the
minimum parameter buffer for eight clusters. No policy controller
configuration. Values from the J775D ADT.
- hw/t6050.rs CONFIG_ULTRA, one of the configurations the ID registers
select at probe (variant 6, two dies), with the UAT policy this board has run with:
tables in no-map reservations, every table change written back,
page-by-page TLB invalidation, the handoff's no-slot value without the lock,
and the handoff byte after the flush records 1. Crash logs in
fw-data. Its core layout is eight clusters of ten cores, with the
eight-cluster operand-state layout (OperandState::EIGHT_BY_TEN).
- M5 GPUs are matched on the board's cluster and core-slot counts,
the values the M5 layouts are sized from, not on enabled cores: the
J775D has 64 of its 80 cores enabled. The T6050 core layouts drop
their own copy of the counts.
- The M5 firmware build (V26A428_M5): the 26A428 variant with the M5
command set and no host power hold around render-pair registration
(Variant::registration_power_hold). The bare-metal M5 firmware powers
the cores for work by its own policy: under a hold, J775D's
core-power witness reads unpowered until the hold is released, so
taking one only times out.
- Gpu::boot_m5: link the kernel lower root's tables the firmware reaches
(entries 1, 7 and the canonical arena's 8) before either role starts,
boot both roles, adopt the published roots, build the M5 graph in the
shared kernel window and bind its metrics object, attach the host
command port to the graph's views, then the M5 preparation, InitData
to the primary and the secondary, POWER_ON_DONE, and wait for the
opening records. A failed bootstrap keeps the session. The kept
session's callbacks run the module's code, so the module is pinned
until reboot before either role starts. This is G15's try_module_get
pin, moved from g15/ to retain.rs and retain.c so both backends share
it. Once the module's removal has begun, nothing is started and the
session is freed unstarted. The graph builder, the M5 preparation and
the metrics binding are the M5 tree's.
[ rebased onto integration/aurora 33bec40: conflicts in mmu.rs only; the handoff init takes the byte beside integration's T8152 no-peer check ]
Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On the M5 Ultra Mac Studio (J775D) the driver would write its firmware tables to whatever GPU firmware the boot loader left loaded, unchecked. It now drives only the known build, and any other image fails the GPU probe before a single GPU write, with the rest of boot unaffected. On bare metal nothing vouches for the firmware the boot loader left in fw-text: the driver would write the 26A428 firmware's InitData graph to whatever was loaded. J775D now names the build it admits (Firmware::Identified), so Gpu::new identifies the loaded TEXT among its images before anything is written to the GPU, as for the other identified G17 SoCs. fw-text holds the primary's TEXT then the secondary's, each with its own pair of entropy records, and the boot loader refills eight ranges per boot (two sections and two header load fields per role). The build zeroes all of them, so the live image and the firmware file hash alike (c35354407602...ce9cc8251). A mismatch logs the measured identity and the probe fails before any GPU write; the rest of boot continues. A digest pinned per boot would refuse the genuine firmware on the next boot. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
A Rust DRM driver without core_object_args() read and wrote past the end of objects the DRM core created for it, such as a dma-buf imported from another device; on the M5 Ultra Mac Studio (J775D) this bug in an earlier GPU driver tree panicked the kernel and kept the desktop from starting. Such a driver (tyr, in this tree) now refuses the import with EINVAL; asahi has core_object_args() and is not affected. Handle lookups and every Object<T> accessor assume that each GEM object of the device is a whole Object<T>. The DRM core creates imported and dumb objects through gem_create_object, which the shmem abstraction installs only for drivers with core_object_args(). For any other driver the core allocates a bare drm_gem_shmem_object instead, and the Rust side then reads and writes past its end. Commit 2dc22a1 ("rust: drm: gem: shmem: let drivers allocate the objects the core creates") lets drivers with core_object_args() allocate them; this completes it for the others. Install gem_prime_import_sg_table and dumb_create only with gem_create_object. A driver without core_object_args() then refuses an import from another device with -EINVAL instead of corrupting memory. In this tree that is tyr; asahi has core_object_args() and keeps both. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On the M5 Ultra Mac Studio (J775D) the GPU never left its base performance state (338 MHz) under any load, so every GPU workload ran at the lowest clock. The firmware's power controllers now get the Ultra's own power model and ramp the GPU up. The M5 builder installs the policy controllers' configuration only for a board whose leakage calibration words match (J714). J775D has none, so every controller word stayed zero, and the firmware never left its base performance state (P1, 338 MHz) under any load. Give J775D its own arm, as J714 has one: encode_m5_policy_controller_defaults_j775d starts from the J714 defaults and writes the Ultra's power model over them: - the modeled maximum power, 345262 mW, in the policy's maximum and ceiling words, and from there in Region C's host power budget; - the relative power curves of the main and auxiliary domains; - the leakage inputs of eight clusters and two dies; - the controllers' gains and utilization thresholds; - the temperature-sensor channel masks of both dies. The model uses synthetic leakage inputs, valid for every J775D, so the J775D arm needs no calibration words. J714 is unchanged. The J775D arm follows the shape of Erik Bourget's J716c controller defaults (f7f650b887cd, not carried here): the J714 defaults first, then the board's own values over them. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On GPUs with independent queues, QUEUE_CREATE had no per-client limit, so one unprivileged client could open queues until the device's execution contexts were gone. Every other process, the compositor included, then failed to create a queue with EBUSY: a GPU denial of service for the whole seat. Queues now count against the process that created them, identified by its mm as the driver's memory accounting attributes buffers, across all of its open files, so opening the device again does not reset the count. A process may always hold up to half of the device's queues. Beyond that, its next QUEUE_CREATE fails with EBUSY if it would leave fewer than an eighth of them free (7 of 58 where all execution contexts are available) while another process holds a queue. A process alone can still use every queue the GPU can still create; one beside a compositor holding three gets 48 of 58, and the others keep 7 for the compositor and anything started later. The limit follows each GPU's queue budget, the one GET_PARAMS reports. GPUs without independent queues are unchanged. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…er GPU VM Each sparse tile was a 64-page physically contiguous allocation, 1 MiB with 16 KiB pages, of which the page tables read only the first UAT page. Every VM that did a sparse-tile bind allocated two, so any client could pin 2 MiB of high-order memory per VM it created, exhausting or fragmenting contiguous memory for the rest of the system. A tile is now one UAT page. The allocation's order is derived from the UAT page size, so the tile stays naturally aligned to a UAT page whatever the kernel page size. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…r overwrite kernel memory On GPUs whose page tables the firmware builds in reserved memory (the T6040, T6041 and T6050), a page-table walk followed any table descriptor the firmware or bootloader had written, and accepted a child table anywhere in System RAM. A corrupted or unexpected descriptor below the shared kernel root would then have the walk store PTEs into an arbitrary kernel page. A table page must now be in the reserved regions or be one the driver allocated; anything else fails the walk with EIO. Freeing already refuses tables the driver does not own, so only the write path was exposed. The firmware's own tables on these boards are reserved no-map regions, and every table the driver adds is recorded when it is allocated, so no legitimate walk is refused. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…pletion and scheduler pages On M5, the render completion stamps, each context's scheduler and work-state pages, and each compute queue's support page were mapped for both the firmware and the GPU. The kernel trusts what they hold. They sit in the kernel's upper half, which every execution context includes. Whether user shaders could reach that half was never established. This removes the GPU permission either way: on M5 these pages are now firmware-only. On the Studio, every GPU path ran clean with them firmware-only, so the GPU itself doesn't need them. Scope, by page set: - Render completion stamps (initdata/m5.rs): allocated only on M5. - Scheduler pages (context.rs): M5 takes them from the retained pool, Neo allocates its own. Firmware-only on M5 only; Neo is unchanged. - Work-state pages (context.rs): shared code, allocated on Neo too. Firmware-only on M5 only; Neo is unchanged. - Compute support page (queue/compute.rs): Neo allocates a larger one for its own use. Firmware-only on M5 only; Neo is unchanged. set_fw_cached_prefix now derives the cached prefix from the mapping's own protection, changing only the cache attribute, instead of rewriting it to the firmware-and-GPU protection. Its readback already refused any change other than the cache attribute. So a firmware-only pooled object used to fail queue creation with EFAULT, and every source that succeeded is one for which the derived protection is the same as before. That covers every pooled family on Neo and M5 today, all firmware-and-GPU shared, so the change is identity there. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…e kernel validated them Every client VM had a read-write view of its queues' kick rings, the entries the kernel builds from validated state for each command: queue and descriptor addresses, dependencies, QoS slot, event masks and the register programs' addresses. A client's GPU work could therefore rewrite an entry after the kernel had built and checked it, before the firmware consumed it. A render pair's rings also stay mapped in every VM that ran on them. Client views of kick rings are now read-only. The host writes kick entries through the kernel's own mapping and the firmware reads them through its own; neither uses the client's view, and nothing in the driver reads an entry back. The client's view is there for the GPU's reads, as the descriptor rings' client views, already read-only, are. The kernel's lower mappings keep their permissions. On M5, the firmware's mappings of the render kick rings and of the compute and render command descriptors sit in the kernel's upper half, which every execution context includes, and also gave the GPU access; a compute ring's firmware mapping already had none. They are now firmware-only on M5, as a compute ring's is: the GPU reads both only at their lower addresses. Neo is unchanged. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…emory On T6050 with display firmware 27, when the display co-processor's firmware named a buffer in a request that was none of the host's pending command buffers, the host resolved the address through the whole IOMMU domain and copied up to 1 MiB to or from whatever it translated to, ignoring the mapping's permissions. A reply could thus be written into memory the co-processor may only read, such as another process's framebuffer or an imported buffer, and a request could read any memory the co-processor can reach. An address that translated to a device's registers was mapped cacheable and copied through, which can take the system down. Only the firmware's own retained mappings are now followed, a reply needs a mapping that grants writes, and an address in Linux's RAM, in any claimed memory resource or below all of Linux's RAM is refused: on Apple SoCs every device register window lies below DRAM, so that also covers registers no driver claimed. The copy goes through a write-combined mapping, as the RTKit buffers in the same firmware segments are, since the co-processor is not DMA-coherent. A firmware-27 RTKit buffer placed below DRAM is refused as well. The DART driver gains a resolver for this that refuses any address Linux mapped itself and returns the protection the firmware's leaves grant, for the four-level subtrees and root slots it retains. DRM_APPLE now follows the DART driver's build choice, since it calls into it. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
… under memory pressure Two kinds of G17 work signal job fences: the event work, which completes jobs, and each scheduler's timeout work, which fails timed-out ones. Memory reclaim may wait on those fences, but neither ran on a reclaim-safe workqueue. The event work ran on an M5 driver queue allocated without WQ_MEM_RECLAIM, or on system_highpri_wq; the timeout work ran on system_percpu_wq, drm_sched's default. When a pool has no idle worker and creating one needs memory, that work cannot run, and neither the fences nor reclaim make progress. Send all of it to one reclaim-safe queue, aurora_g17_events. On M5 it is unbound and high priority as before, so the event work still follows the submitting CPU; elsewhere it is per-CPU and high priority, the counterpart of system_highpri_wq, so the event work runs where it did. Every scheduler takes the queue as its timeout queue and keeps a reference until it has been finalized. Their run and free work already used reclaim-safe queues. For that, the Rust OwnedQueue gains reclaim-safe unbound and per-CPU constructors (restrict() refuses a per-CPU queue), and the Rust DRM scheduler binding's new_with_queues() takes an optional submission queue and an optional shared timeout queue, in place of new_with_submit_wq(). Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…the statistics tags and power rule from InitData The report rings now take the statistics record tags and a control record's power rule from InitData (statistics_types(), control_asserts_gpu_power()), and the reports KUnit tests compare G17's tags with M5's (fw::m5::STATISTICS_TYPES). Build those InitData methods, M5's tag mask and M5's power rule from the production sources into the fixture, with the fixture's InitData on the G17 path as before, so the rings, reports and every mutation run against the code the driver runs. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
- The active MCC mask names all eight AMCCs, matching the slot 3 windows, instead of the inherited four. - The two topology words: 16, and the core count (40, all cores). J714 keeps the inherited values, and J775D its own. Signed-off-by: Erik Bourget <erik@ebourget.net> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The M5 Max's controller defaults were J714's, applied only to a part with J714's calibration words, which no M5 Max has. Give it its own: the J714 defaults, including the relative power curves, with the leakage of its four clusters, its base and AFR values, a maximum power of 196098 mW, and the found masks of its AON PTD records, applied for the J716c calibration words. As on J714, a unit whose calibration words differ keeps the default budget. Signed-off-by: Erik Bourget <erik@ebourget.net> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
The M5 Max (J716c) already has its board data, but its configuration still names no firmware and probe refuses it as having no bare-metal GPU tables. Give it the M5 Ultra's bare-metal profile: both roles publish their kernel roots, the secondary's in `pagetables`, each asks for its crash log inside `fw-data`, and the UAT policy is the Ultra's. Admit the G17C firmware build of both roles, with the boot-filled ranges zeroed as on the Ultra. Only the M5 Pro is refused at probe now. The firmware identity test covers the Max's image too. Tested on a J716c: the GPU boots both roles and runs the desktop through zink and Vulkan. Signed-off-by: Erik Bourget <erik@ebourget.net> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Bind the T6050 GPU through "apple,agx-g17s", the compatible its M5 Max
("apple,agx-g17c") and M5 Ultra ("apple,agx-g17d") nodes fall back to,
in place of "apple,agx-t6050", which no binding documents. The GPU's ID
registers still choose the board's configuration.
Signed-off-by: Erik Bourget <erik@ebourget.net>
[ onto aurora-silicon#1012 rebased on integration/aurora 33bec40: conflicts in driver.rs only; the G17S entry probes through ProbeConfig::G17M5, the series' name for the M5 Pro/Max/Ultra entry beside integration's T8142 ProbeConfig::M5 ]
Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…acks An rmmod of aurora that raced a GPU probe on M4 (G16), M6 (G18) or the M5 RAM-boot path could unload the module under a GPU firmware whose RTKit and mailbox callbacks run its code. Each of these backends now refuses to start the firmware once the module's removal has begun. They pinned the module with __module_get(), which does not stop an unload already under way: a deferred or asynchronous probe can run after rmmod has passed its reference check, take the reference anyway and start the firmware while module exit unloads the code. try_module_get() fails once removal has begun. G15, and G17 on M5, pin with it through the shared pin in retain.rs and retain.c; the other backends now use the same pin, each with its own flag: - G16: admission pins the module before it holds the GFX power domain and fails with ENODEV, holding nothing, once removal has begun. The firmware start and Gpu::retain only confirm the pin. The C helper asahi_g16_module_get() goes. - The M5 RAM-boot path (M5Runtime::prepare): the pin is still taken before either CPU starts. Once removal has begun, prepare fails with ENODEV and the unstarted session is freed. - G18: the pin is taken before the session is marked as attempted. Once removal has begun the stage fails with ENODEV with nothing started, and the attempt is not marked. Build-checked only: there is no M4, M5 RAM-boot or M6 hardware here. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
An rmmod of the display driver that raced a DCP probe, a display attach or an external start request could unload the module under a DCP firmware whose RTKit callbacks run its code. These paths now refuse once the module's removal has begun. They pinned the module with __module_get(), which takes the reference even after rmmod has passed its reference check, so the unload goes on under the firmware. Each now uses try_module_get() and backs out what it had set up: - The firmware 26.6 and 14.7 panel sessions: pinned before the mailbox is registered; -ENODEV with nothing started. The reference is given back if RTKit init fails. - The external DCP's one-shot start (its sysfs request and a display attach) and the external scanout pattern request: the request is withdrawn and no work is queued. - A retained live session (dcp_pin_live_session): -ENODEV before any reference is taken, as for its allocation failure. - A refused takeover: the pin is taken before the takeover trials, while the bind can still unwind. A refusal keeps it; it is given back once every trial passes. While the module is live each path takes the same reference as before. Build-checked only: no unload race was run on hardware. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…, with firmware-27 cases added The firmware-27 display support makes the extracted production code name DCP_FIRMWARE_V_27_0 and new fields and helpers, so 20 apple-dcp fixtures stopped compiling: the AFK service-init parser gained an EPICUnit-first argument and service ops an init_props hook, parser.c fills struct dcp_dptx_caps from dcp-peer-v27.h, dcp_get_disp_regs() records firmware-physical register bases, the IOMFB dispatcher size-checks firmware-27 callbacks, the DPTX lane policy keys on dcp_is_external_h17p() and the hotplug callback completes typec_display_ready. The dictionary record the desktop panel identity uses moved to iomfb.h as struct dcp_dict_passthrough_req. The fixtures gain those definitions and stubs, and their existing checks run unchanged. Where firmware 27 takes a branch a fixture already drives, it is checked too: dpavserv uses AFKV2 on the legacy endpoint without waiting, EPICUnit wins over interface-id in either order, and powerlog takes a framed report's takeover hint but not the desktop-only headerless pairs. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…as no room for another queue When QUEUE_CREATE found no room (no render channel pair left beside the installed compute channels, or no free execution context while a closing queue still held one), it gave back the logical queue slot it had just claimed and then waited for a slot to be returned. Giving the slot back woke the slot waiters, the creator itself included, so its wait ended at once: the ioctl spun on a CPU, with the device mutex taken on every turn, until its timeout. One unprivileged process could keep a CPU busy that way; in testing it refused over half a million times in 29 seconds. The render-channel check now runs before the slot is claimed, so a refusal claims nothing. A creator that gives back a claimed slot to wait for a context now waits from the sample after its own return: other waiters still wake, and the creator sleeps until a slot or context is actually returned or its timeout passes. QUEUE_CREATE still fails with EBUSY after the timeout. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…airs in firmware, so a second render pair never waits on the host An owner (one logical queue) holds one render pair today. Before it can hold two, its renders whose attachments overlap must stay ordered when they land on different pairs, and that ordering must not be a host wait: the old plan returned Plan::Wait for own overlaps on two pairs. dj's b141ca9 orders a render after overlapping renders of other owners in the VM, in firmware. This extends it to the owner's own renders on its other pair, which his plan held with a host wait. This uses the mechanism other owners of the VM already get. Under the device mutex, publication_barriers names the newest published fragment kick of every other pair whose live same-VM render overlaps. It now includes the owner's own renders on its other pair that the render's queue prefix (wait_through[0]) does not already cover. Those were left out because an owner had one pair. hazard::plan: - Own overlaps prefer the pair that holds them (Plan::Join). With overlaps on two own pairs it prefers the pair of the newer overlap. - pick takes the preferred pair, or else the owner's least-loaded other pair. Either is ordered: ring order on the same pair, the barrier across pairs. So a full preferred pair never makes the render wait. - Plan::Pair (strict) remains only when no barrier slot is left. That is the case with PUBLICATION_BARRIERS other pairs of the VM and a foreign overlap. - In that crowded case, a render with own overlaps on two pairs waits, as a crowded publication already does. It needs eight same-VM pairs, so it never happens on a one-queue workload. The quarantine checks (refusal, the admission wait, admits_render, spared_quarantined) looked at the owner's first pair only. They now look at any pair the owner holds through State::owner_quarantine. A quarantined sibling is not bypassed through the healthy pair. The owner is spared only if every quarantined pair of its is spared. Locking and ordering: - plan, pick and owner_quarantine run under the pool's state lock, as before. - publication_barriers runs under the device mutex and the state lock. The device mutex totally orders publications. - An owner publishes in submission order: inline publication runs only with an empty backlog, and the ordered run_job worker publishes one command at a time. So every earlier own render already carries its fragment kick when a later one publishes, and the barrier sees it. - Tile loads and stores happen only in fragment work, so ordering the fragment kick is enough. The tiling kick keeps its prefix rules. - A barrier on the same pair is skipped, as before: one fragment ring completes in kick order. With RENDER_PAIRS_PER_OWNER = 1 no owner holds two pairs. Join then behaves as Pair, and no own entry sits on another slot, so behaviour is unchanged. KUnit: - asahi_g17_hazard_plan covers preference, prefix cover, the newer of two pairs, the foreign barrier beside them, and the barrier slot. - asahi_g17_owner_pairs covers the Join fallback when the preferred pair is full, any-pair quarantine, and the own barrier against prefix cover. Suggested-by: DjDeveloperr <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
…om its own pair count, so a queue on two pairs can keep both rings full drm_sched fixes a scheduler's credits when it is created. Those credits were one pair's ring (RENDER_DEPTH, 32), so a queue on two pairs would have been held at one ring's depth. Its render pool's per-pair extras and its sibling limit read the device-wide constant. dj's 22516bf45e61 sized credits as pairs × depth. This keeps that per queue, so a queue's credits follow the pairs it may hold. Each logical queue (Backend) now records the render pairs it may hold, `pairs`, when it is created. Three things follow from that one value: - Its render scheduler's credits are RENDER_DEPTH x pairs, through job::Backend::render_pairs (default 1). - required_blocks sizes its render pool's compute-pool extras for `pairs` pairs. - Admission's claim_sibling takes another pair only while the owner holds fewer than `pairs`. acquire_render, try_acquire_render, pick and acquire carry the value from the queue. A queue never mixes the two sizings, so a later change of the device's pair count (the next commit's switch) applies only to queues created after it. `pairs` is still RENDER_PAIRS_PER_OWNER (1) here, so credits, pool size and claiming are unchanged. Locking and ordering: `pairs` is immutable after Backend::new. The scheduler reads it once, in Scheduler::new, before the entity exists. Admission reads it under the pool's state lock, as it reads every other admission input. Suggested-by: DjDeveloperr <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
… shared QID capacity, 9-15% faster heavy 1080p rows at depth 8 dj's 87cab74 ran each queue on two pairs. Ryan's shared capacity (780956a) protects one render pair per execution context and shares the rest, and set one pair per queue to fit it. Most of the two-pair machinery stayed behind the constant: acquire's least-loaded fallback, claim_sibling, warmable_sibling and ensure_render's sibling warm-up. This restores two on G17D and keeps Ryan's protected pair, so the second comes from the shared surplus. An owner's overlapping renders on its two pairs are ordered in firmware, by dj's barriers, never by a host wait (the first commit of this series). M5 Ultra, gpubench, 1080p, us per submit, one boot, client pinned, three runs each: | row | 1 pair | 2 pairs | 1 pair again | |---|---|---|---| | fill d8 | 41.98 / 41.95 / 41.97 | 38.13 / 38.13 / 38.14 | 41.97 / 41.98 / 42.00 | | geom d8 | 39.10 / 38.91 / 39.11 | 33.19 / 33.22 / 33.21 | 38.83 / 39.16 / 38.16 | GPU time per render is unchanged (41.8 and 39 us): the gain is the two pairs overlapping. With this commit alone a depth-2 queue switches pairs on almost every render and loses time: fill d2 95-102 -> 126, geom d2 104-117 -> 127. The next commit keeps such a queue on one pair. What changes: - g17::pairs picks the count at probe: 2 on G17D boards (g17d_forms(), as the other G17D forms are chosen), 1 everywhere else. Each queue samples it once at creation, for its credits, pool and pair limit (previous commit). - The constant becomes the per-variant maximum RENDER_PAIRS_MAX = 2, and hazard::MAX_OWNER_PAIRS follows it. - max_in_flight_per_queue reports the count. - ensure_render's early return follows the queue's own count. The second pair comes only from surplus: - render_reserve still counts one pair per open queue. The kick.rs assert that pinned the constant to 1 now states that, so queue_limit and the capacity guarantees are unchanged. - claim_sibling takes a sibling only from a released or unowned slot, and only while a pair can still be built (build_room). - reassign_unused_spare gives an unused spare only to an owner with no pair, as before. Completion order across one queue's two pairs, which needs no code: - The driver's completion fences, the ones userspace sees, each have an independent timeline (fence.rs), so they may signal out of order. - drm_sched's finished fences share the entity's context. They are internal and never exported. free_job takes jobs from the head of pending_list, so a render that finishes early on the other pair is freed, and its credit returned, after its predecessor. That delays a credit; it never waits on the GPU. - Firmware flushes a context's work-state nodes in word order (377324b), so retirement evidence stays ordered per pair. Memory: on G17D every render pool carries two pairs' compute-pool extras. Locking and ordering: - The count is a static, written once at probe before any queue exists, and read in Backend::new. - Admission state (owners, refs, build_room) changes only under the pool's state lock, as before. - Sibling construction is off-lock under a host lease (warmable_sibling), as integration has it. KUnit asahi_g17_two_pairs: - a two-pair owner spreads its depth to 2 x RENDER_DEPTH over a surplus sibling, then is held; - without build room no sibling is claimed, and a spare goes only to an owner with no pair; - a one-pair owner claims no sibling. Suggested-by: DjDeveloperr <hey@djdev.me> Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
… has a backlog, so depth-2 rows keep one pair's latency (20-28% faster than always splitting) With two render pairs per queue (previous commit), acquire took the owner's idle sibling whenever one existed. At depth 2 that switched pairs on 98% of renders, and each render then waited, across pairs, for the one before it. A two-pair queue's next render now stacks on its least-loaded busy pair while that pair holds at most sibling_backlog() renders (1). Only after that does it take the idle sibling. At depth 1-2 a queue stays on one pair. A deeper queue still spreads, because its third render in flight finds a backlog. A one-pair queue takes the existing path unchanged. M5 Ultra, gpubench, 1080p, us per submit, one boot, client pinned. That boot also carried the per-submit fixes, which speed up the depth-2 and geom rows: | row | 1 pair | 2 pairs, always split | 2 pairs, backlog 1 | backlog 16 | |---|---|---|---|---| | fill d2 | 82.2 | 125.2 / 129.0 | 78.3 / 81.9 | 80.3 | | geom d2 | 84.4 | 118.8 / 129.5 | 84.3 / 83.5 | 90.5 | | fill d8 | 41.97 | 37.75 / 38.14 | 38.13 / 38.14 | 41.95 | | geom d8 | 38.98 | 31.50 / 31.82 | 31.85 / 31.84 | 38.23 | Backlog 1 brings depth 2 back to one pair's time and keeps the depth-8 gain. A deep backlog (16) gives the depth-8 gain up. This series alone (two pairs, backlog 1), two runs: fill d2 92.8 / 91.0 and geom d2 102.1 / 102.0, against 126.0-126.5 and 127.2-127.7 always splitting on the same series without this commit, 20-28% faster. Depth 8 stays at the two-pair level: fill 38.14 / 38.15. Locking and ordering: acquire runs under the pool's state lock, as before. Stacking on a busy pair is the existing least-loaded stacking, applied earlier. The pair's ring orders the render after that pair's earlier work, and the queue prefix and the hazard plan order it across pairs, as before. The backlog is a relaxed static: a policy value read per pick, never a sizing. KUnit: asahi_g17_two_pairs gains a_shallow_two_pair_queue_stays_on_its_busy_pair. The spreading test runs with backlog 0. Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
On a J813 (M5 MacBook Air) whose stub is macOS 27.0, the DCP firmware (AppleDCP-1317.1.1~116-t8142dcp, RTKit 3514.0.15) panics right after the first hotplug when it is driven through the H17P interface written for the 26.x firmware: its crash log reads "ap_link: callback failed with: 0x5", apple-drm never binds and the unwind WARNs in devm_clk_match. The 27.0 firmware speaks the T6050's firmware-27 generation. Take DCP_FIRMWARE_V_27_0 for a T8142 whose firmware-compat is 27.0.0, and the default IOMFB method profile there: with the H17G profile every swap fails with status 4. Tested on the J813 under 27.0 (with the clocks of the following DT change): DCP booted, 2560x1600@60, fbcon and sway, no swap failures, no WARNING. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The macOS 27.0 DCP firmware asks for its provider clocks by index into the /arm-io/disp0 clock-ids, 585 and 431. The J813 ADT has no rates for them (its clock-frequencies has 174 entries), so add two fixed clocks at the J716c's rates for its clock IDs 361 and 458; the J813 panel runs at 2560x1600@60 with them. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
DjDeveloperr
force-pushed
the
funkzy/t6050-gpu-on-integration
branch
from
November 8, 2026 17:11
b1615e3 to
0dd0833
Compare
RyanTheTide
reviewed
Nov 10, 2026
RyanTheTide
left a comment
Contributor
There was a problem hiding this comment.
- Rebase onto the current head of
funkzy/t6050-gpu-on-integration(0dd0833). That drops the 13 older base commits, which the branch now carries in rewritten form. Your two commits (37a9e8a, 42db926) replay onto it without conflicts. t8142-j813-display.dtsiwon't pass the binding. InDocumentation/devicetree/bindings/display/apple,dcp.yaml, every non-T6050 DCP getsapple,clock-ids: falseandclock-names: [clock-154, clock-194]. The node now setsapple,clock-ids = <585 431>andclock-names = "firmware-0", "firmware-1". Extend the binding forapple,t8142-dcpon firmware 27, or follow the existing schema, and runmake dtbs_checkfort8142-j813.dtb.- The two fixed clocks use the J716c's rates (810000000 and 521064992) for different clock IDs. The description still lists the real rates as open. Please use the J813's own rates or, if the firmware never uses the rate, say so in the comment and the commit message.
- Replacing
clocks = <&clkref>changes the clock a J813 on 26.x firmware gets.dcp_check_firmware_version()still sends 26.x down the H17P path, and that path'sdevm_clk_get(dev, NULL)now returnsdcp_fw_clk585(810 MHz) instead ofclkref. Keep the 26.x path on its old clock, or make the probe reject 26.x on T8142 with a clear message.
Contributor
Author
|
Thanks for the review. #1413 replaces this PR. It carries #1012 rebased onto integration/aurora,
Closing in favour of #1413. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1012 (funkzy/t6050-gpu-on-integration), which brings the firmware-27 DCP path.
With the J813 (M5 MacBook Air) stub on macOS 27.0, the J813's DCP firmware (AppleDCP-1317.1.1~116-t8142dcp, RTKit 3514.0.15) panics right after the first hotplug when it is driven through the H17P interface: its crash log reads "ap_link: callback failed with: 0x5", apple-drm never binds, and the unwind WARNs in devm_clk_match. The 27.0 firmware speaks the T6050's firmware-27 generation instead.
DCP_FIRMWARE_V_27_0, with the default IOMFB method profile (with the H17G profile every swap fails with status 4).J813s on 26.x are not a target any more: the DT change replaces the H17P path's
clkref.Tested on the J813 under 27.0, on the J813 stack with this firmware-27 path merged: DCP booted, 2560x1600@60, fbcon and sway, no swap failures, no WARNING. On this branch:
drivers/gpu/drm/apple/and the J813 DTB build (clang 22).Open: the real rates of 585/431, and whether the J813's H17G alpha/powerlog semantics matter on firmware 27.
cc @Acelogic @DjDeveloperr @RyanTheTide @LiamRay10