}
static void
+cp_start_bin(uint32_t *dwords, uint32_t sizedwords, int level)
+{
+ uint64_t ibaddr;
+ uint32_t ibsize;
+ uint32_t loopcount;
+ uint32_t *ptr = NULL;
+
+ loopcount = dwords[0];
+ ibaddr = dwords[1];
+ ibaddr |= ((uint64_t)dwords[2]) << 32;
+ ibsize = dwords[3];
+
+ /* map gpuaddr back to hostptr: */
+ ptr = hostptr(ibaddr);
+
+ if (ptr) {
+ /* If the GPU hung within the target IB, the trigger point will be
+ * just after the current CP_START_BIN. Because the IB is
+ * executed but never returns. Account for this by checking if
+ * the IB returned:
+ */
+ highlight_gpuaddr(gpuaddr(&dwords[5]));
+
+ /* TODO: we should duplicate the body of the loop after each bin, so
+ * that draws get the correct state. We should also figure out if there
+ * are any registers that can tell us what bin we're in when we hang so
+ * that crashdec points to the right place.
+ */
+ ib++;
+ for (uint32_t i = 0; i < loopcount; i++) {
+ ibs[ib].base = ibaddr;
+ ibs[ib].size = ibsize;
+ printf("%sbin %u\n", levels[level], i);
+ dump_commands(ptr, ibsize, level);
+ ibaddr += ibsize;
+ ptr += ibsize;
+ }
+ ib--;
+ } else {
+ fprintf(stderr, "could not find: %016" PRIx64 " (%d)\n", ibaddr, ibsize);
+ }
+}
+
+static void
cp_wfi(uint32_t *dwords, uint32_t sizedwords, int level)
{
needs_wfi = false;
CP(REG_WRITE, cp_reg_write),
CP(SET_CTXSWITCH_IB, cp_set_ctxswitch_ib),
+
+ CP(START_BIN, cp_start_bin),
};
static void
<doc>sets the 64-bit BIN_MASK register in the PFP</doc>
<value name="CP_SET_BIN_MASK" value="0x50" varset="chip" variants="A2XX-A4XX"/>
<doc>sets the 64-bit BIN_SELECT register in the PFP</doc>
- <value name="CP_SET_BIN_SELECT" value="0x51"/>
+ <value name="CP_SET_BIN_SELECT" value="0x51" varset="chip" variants="A2XX-A4XX"/>
<doc>updates the current context, if needed</doc>
<value name="CP_CONTEXT_UPDATE" value="0x5e"/>
<doc>generate interrupt from the command stream</doc>
-->
<value name="CP_REG_WRITE" value="0x6d" varset="chip" variants="A6XX"/>
+ <doc>
+ These first appear in a650_sqe.bin. They can in theory be used
+ to loop any sequence of IB1 commands, but in practice they are
+ used to loop over bins. There is a fixed-size per-iteration
+ prefix, used to set per-bin state, and then the following IB1
+ commands are executed until CP_END_BIN which are always the same
+ for each iteration and usually contain a list of
+ CP_INDIRECT_BUFFER calls to IB2 commands which setup state and
+ execute restore/draw/save commands. This replaces the previous
+ technique of just repeating the CP_INDIRECT_BUFFER calls and
+ "unrolling" the loop.
+ </doc>
+ <value name="CP_START_BIN" value="0x50" varset="chip" variants="A6XX"/>
+ <value name="CP_END_BIN" value="0x51" varset="chip" variants="A6XX"/>
</enum>
</reg32>
</domain>
+<domain name="CP_START_BIN" width="32">
+ <reg32 offset="0" name="BIN_COUNT" type="uint"/>
+ <reg64 offset="1" name="PREFIX_ADDR" type="address"/>
+ <reg32 offset="3" name="PREFIX_DWORDS">
+ <doc>
+ Size of prefix for each bin. For each bin index i, the
+ prefix commands at PREFIX_ADDR + i * PREFIX_DWORDS are
+ executed in an IB2 before the IB1 commands following
+ this packet.
+ </doc>
+ </reg32>
+ <reg32 offset="4" name="BODY_DWORDS">
+ <doc>Number of dwords after this packet until CP_END_BIN</doc>
+ </reg32>
+</domain>
+
</database>