aboutsummaryrefslogtreecommitdiffstats
path: root/mes/hw (follow)
Commit message (Collapse)AuthorAge
* MEC/PM4 round 9: stop the KIQ port on cost/benefit, name the cheaper routeuser2026-09-28
| | | | | | | | | | | | | | | | | | | | | | | Ported the last two prerequisites from gfx_v11_0.c: RS64 compute enable turns on all four pipes together with MEC_HALT=0 (CP_MEC_RS64_CNTL 0x04000000 -> 0x3c000000), and kiq_init_register programs CP_MEC_DOORBELL_RANGE_LOWER/UPPER, outside which the CP silently ignores doorbells. Neither closed the gap. With the right slot, CP_HQD_ACTIVE=1, the scheduler pointed at the queue, all pipes active, the MEC unhalted and the doorbell range programmed, the queue still does not retire a NOP. The remaining candidate is the MEC firmware's own per-pipe initialisation, since amdgpu loads MEC microcode per pipe and the RS64 MEC likely only services pipes initialised at load time -- a substantially larger port. Cost decides it: each failed attempt leaves an undequeueable HQD and GRBM_STATUS 0xa800302c that only a cold ATX cycle clears, and three have now been spent on one open question. Stopping the thread. The cheaper route is recorded for whoever picks it up: MAP_QUEUES sits at 0x3241c in the validated PM4 table, inside the ~12 KB dispatcher sub_31360, and whether any path from that label consults a privilege bit is a bounded static reverse with no hardware cost and no power cycles.
* MEC/PM4 round 8: port amdgpu's KIQ slot selection; queue activates, still stallsuser2026-09-28
| | | | | | | | | | | | | | | | | | | | | | | | Continuing round 7's blocker by reading amdgpu's KIQ bring-up and porting it. Three concrete fixes. The KIQ slot was wrong, not merely unallocated: amdgpu_gfx_kiq_acquire scans the queue bitmap downward requiring queue == 0, and gfx11 has num_mec = 1, so ring->me = mec + 1 = 1. tinygrad hardcodes me=2/pipe=1, a VF layout, which is exactly why round 7 saw CP_HQD_ACTIVE = 0. The real slot is me=1 pipe=3 queue=0, reachable through setup_ring's ordinary path at idx=12 so the MQD is still built by driver code -- CP_HQD_ACTIVE now reads 1. The HIQ pointer encoding is RLC_CP_SCHEDULERS = (me<<5)|(pipe<<3)|queue|0x80 per gfx_v11_0_kiq_setting. And because gfx11 is RS64, per-pipe enables live in CP_MEC_RS64_CNTL rather than CP_MEC_CNTL; it read 0x04000000, only pipe0 active. Still stalled: with the right slot, an active HQD, the scheduler pointed at it and pipe3 enabled, CP_HQD_PQ_RPTR stays 0 while the doorbell and CP_HQD_PQ_WPTR_LO both reach the queue. A pipe-0 queue on the identical code path retires the same NOP, so the submission mechanism is sound and the gap is pipe-3 specific -- most likely the per-pipe HPD/EOP programming from amdgpu's compute resume. CP_MEC_RS64_CNTL restored to its original value. MAP_QUEUES remains untested, but the slot, scheduler encoding and pipe-enable register are now known and verified, leaving one named piece.
* MEC/PM4 round 7: HIQ plumbing blocked, blocker characterised preciselyuser2026-09-28
| | | | | | | | | | | | | | | | | | | | | | Attempted to stand up a KIQ/HIQ ring to give round 6 its missing control. Cleared two obstacles: tinygrad's mqd_paddr has 2+is_vf entries while setup_ring(kiq_xcc=0) indexes 2 (fixed by appending an allocation so the driver's own MQD code runs unchanged), and the KIQ's doorbell index 0 is outside the apertures AM enables (re-pointed at MEC_RING0+4, an index the compute probe had already rung). Did not clear the third: CP_HQD_ACTIVE reads back 0 after setup_ring, so the CP rejects the queue and no NOP retires. Root cause is that tinygrad's KIQ path is VF-only and hardcodes me=2/pipe=1/queue=0, while amdgpu picks them dynamically via amdgpu_gfx_kiq_acquire() and additionally needs the HPD EOP region, MEC pipe enablement and the KIQ doorbell aperture -- an amdgpu KIQ port rather than a patch. The MAP_QUEUES chain therefore stays open and untested, with no claim in either direction. It would have been easy to combine round 6's stall with this round's dead KIQ into "MAP_QUEUES is gated everywhere"; neither result supports that, because a queue that never activates cannot refuse anything.
* MEC/PM4 round 6: MAP_QUEUES chain is untested, not closeduser2026-09-28
| | | | | | | | | | | | | | | | | | | | | | Round 5 closed the direct route (unprivileged queues cannot write registers), so the follow-up is the indirect one: use MAP_QUEUES from an unprivileged queue to map a queue whose MQD sets priv_state=1, then write registers through it. That would be a user->kernel chain requiring no memory-safety bug at all. The test is inconclusive and is recorded that way. MAP_QUEUES stalls the queue identically at priv_state=0 and priv_state=1, and identically again after seeding the target MQD with the one the driver had just built. Because the privileged queue stalls too, the stall is not a privilege effect -- MAP_QUEUES is an HIQ/KIQ-pipe packet and is not serviced on an ordinary compute ring. Worth stating because the failure mode is deceptive: a stall looks exactly like the round-5 privilege fault, and without the priv_state=1 comparison this would have been written up as "the gate covers MAP_QUEUES too". The probe's verdict text is corrected to say a stall alone proves nothing. The chain stays open. Testing it needs HIQ submission with a user-owned ring, which tinygrad's AM does not expose (setup_ring(kiq_xcc=0) indexes past its allocated MQD slots) -- a driver-plumbing blocker, not a firmware one.
* MEC/PM4 round 5 [HW]: the user->kernel register boundary holdsuser2026-09-28
PM4 is submitted by unprivileged user queues and WRITE_DATA(dst_sel=register) names a memory-mapped register, so an ungated path would be the user->kernel primitive none of the DMCUB findings can be. Tested as a 2x2 on silicon, because either factor alone is uninterpretable: dst=memory dst=register priv_state=0 wrote refused, queue then faults priv_state=1 wrote wrote, queue alive The memory column proves the packet encoding, ring, doorbell and submission path are correct -- without it, "the register did not change" is equally consistent with a malformed packet, which is exactly what made the first SDMA RB_PRIV=0 run inconclusive. The priv_state=1 row rules out the other explanation, that WRITE_DATA->register is simply unsupported on MEC. Privilege was changed by live-flipping CP_HQD_PQ_CONTROL (0x8509 -> 0xc0008509) on an already-running queue, so that bit is the only difference between the two runs -- the same isolation technique used for SDMA's RB_PRIV. Verdict: the boundary is real and enforced on gfx11. Across both user-submittable engines the pattern is identical -- memory confined by the VM, registers gated by a per-queue privilege bit, and the gate holds. Also fixes the probe's verdict text, which printed the unprivileged conclusion for a privileged run.