diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 164 |
1 files changed, 121 insertions, 43 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 0180da1..40a8791 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -18861,6 +18861,8 @@ struct gsp_phys_gr_mme_release_state { u32 gen; u32 held; u32 win_n; + /* The saved raw window carries the CALL_MME_MACRO(34) DRAW_IAB run. */ + bool draw_ia; u64 push_va; unsigned long due_j; u32 boot_n; @@ -18905,6 +18907,46 @@ module_param_named(sema_gl_mme_pack_release_ms, MODULE_PARM_DESC(sema_gl_mme_pack_release_ms, "Settle delay before the saved-window release carrier fires (clamped 20..5000 ms; default 100)"); +/* + * DRAW_IAB preference (release carrier follow-up): the held-call window that + * matters is the DRAW window, whose method stream carries the + * CALL_MME_MACRO(34) run that expands to DRAW_IAB (mac=0x22). + * CALL_MME_MACRO(j) is method 0x3800 + 8*j, so slot 34 is 0x3910; the + * client encodes it as the ONE_INCR run `a00a0e44` (op 5, count 10, method + * 0x3910, ten data words - c756 push 0x4011978 raw[12]; the same word in + * both c716 held windows and at raw[113] of the c772 728 B stream, whose + * replay executed only 0x33/0x39 for an SA-entry reason outside this + * preference). The scan uses the CALL hold/drop walk's run grammar (op 1/3/5 + * carry 1+cnt words; only op 1/3 walk past the header method), so a + * CALL_MME_DATA(34) port write (0x3914) or another slot's call never + * selects the record. + */ +static bool gsp_phys_gr_mme_window_has_draw_ia(const u32 *win, u32 n) +{ + u32 r = 0; + + while (r < n) { + u32 h = win[r]; + u32 op = (h >> 29) & 7u; + u32 cnt = (h >> 16) & 0x1fffu; + u32 span = 1u, k; + + if ((op == 1u || op == 3u || op == 5u) && cnt && + r + 1u + cnt <= n) + span = 1u + cnt; + for (k = 0; k < span; k++) { + u32 m = ((h & 0xfffu) << 2) + 4u * k; + + if (k && op != 1u && op != 3u) + break; + if (m == 0x3800u + 34u * 8u) + return true; + } + r += span; + } + return false; +} + static u32 gsp_phys_gr_mme_release_due_ms(void) { u32 ms = READ_ONCE(gsp_phys_rmcall_gr_mme_pack_release_ms); @@ -18929,6 +18971,9 @@ static void gsp_phys_gr_mme_release_save(const struct gsp_phys_gr_submit *req, { struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release; unsigned long flags; + bool draw_ia, keep = false; + u32 old_h = 0, old_win = 0; + static u32 prefer_log; if (!READ_ONCE(gsp_phys_rmcall_gr_mme_pack_release) || !req) return; @@ -18947,51 +18992,84 @@ static void gsp_phys_gr_mme_release_save(const struct gsp_phys_gr_submit *req, req->n_pages, req->n_inl, req->n_data); return; } + draw_ia = gsp_phys_gr_mme_window_has_draw_ia(req->stream, + req->stream_n); spin_lock_irqsave(&gsp_phys_gr_mme_release_lock, flags); - s->valid = false; - s->armed = false; - s->fired = false; - s->consumed = false; - s->arm_h = 0; - s->arm_push = 0; - s->h_object = req->h_object; - s->gen = gen; - s->held = held; - s->win_n = win_n; - s->push_va = req->push_va; - memcpy(s->qmd, req->qmd, sizeof(s->qmd)); - s->n_pages = req->n_pages; - if (req->n_pages) - memcpy(s->pages, req->pages, - (size_t)req->n_pages * sizeof(s->pages[0])); - s->n_inl = req->n_inl; - if (req->n_inl) - memcpy(s->inl, req->inl, - (size_t)req->n_inl * sizeof(s->inl[0])); - s->n_data = req->n_data; - if (req->n_data) - memcpy(s->data, req->data, - (size_t)req->n_data * sizeof(s->data[0])); - s->n_data_wins = req->n_data_wins; - if (req->n_data_wins) - memcpy(s->data_wins, req->data_wins, - (size_t)req->n_data_wins * sizeof(s->data_wins[0])); - s->qmd_va = req->qmd_va; - s->qmd_hpa = req->qmd_hpa; - s->push_len = req->push_len; - s->stream_rel = req->stream_rel; - s->stream_n = req->stream_n; - memcpy(s->win, req->stream, (size_t)req->stream_n * 4u); - s->prog_va = req->prog_va; - s->n_prog_binds = req->n_prog_binds; - memcpy(s->prog_bind_va, req->prog_bind_va, - sizeof(s->prog_bind_va)); - memcpy(s->prog_bind_slot, req->prog_bind_slot, - sizeof(s->prog_bind_slot)); - s->valid = true; + /* + * The DRAW window's raw stream is the release payload that can run the + * DRAW_IAB CALL(34); a later held window whose stream lacks the call + * (e.g. a state-only window) must not supersede it. A cancelled, + * released or consumed record is never protected, so the no-DRAW_IAB + * case keeps the historical last-held-window-wins behaviour. + */ + if (s->valid && !s->consumed && s->draw_ia && !draw_ia) { + old_h = s->h_object; + old_win = s->win_n; + keep = true; + } + if (!keep) { + s->valid = false; + s->armed = false; + s->fired = false; + s->consumed = false; + s->arm_h = 0; + s->arm_push = 0; + s->h_object = req->h_object; + s->gen = gen; + s->held = held; + s->win_n = win_n; + s->draw_ia = draw_ia; + s->push_va = req->push_va; + memcpy(s->qmd, req->qmd, sizeof(s->qmd)); + s->n_pages = req->n_pages; + if (req->n_pages) + memcpy(s->pages, req->pages, + (size_t)req->n_pages * sizeof(s->pages[0])); + s->n_inl = req->n_inl; + if (req->n_inl) + memcpy(s->inl, req->inl, + (size_t)req->n_inl * sizeof(s->inl[0])); + s->n_data = req->n_data; + if (req->n_data) + memcpy(s->data, req->data, + (size_t)req->n_data * sizeof(s->data[0])); + s->n_data_wins = req->n_data_wins; + if (req->n_data_wins) + memcpy(s->data_wins, req->data_wins, + (size_t)req->n_data_wins * + sizeof(s->data_wins[0])); + s->qmd_va = req->qmd_va; + s->qmd_hpa = req->qmd_hpa; + s->push_len = req->push_len; + s->stream_rel = req->stream_rel; + s->stream_n = req->stream_n; + memcpy(s->win, req->stream, (size_t)req->stream_n * 4u); + s->prog_va = req->prog_va; + s->n_prog_binds = req->n_prog_binds; + memcpy(s->prog_bind_va, req->prog_bind_va, + sizeof(s->prog_bind_va)); + memcpy(s->prog_bind_slot, req->prog_bind_slot, + sizeof(s->prog_bind_slot)); + s->valid = true; + } spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags); - pr_info("vgsp-gr: MME-CARRY-SAVE h=0x%x win=%u held=%u push=0x%llx\n", - req->h_object, win_n, held, + if (keep) { + if (prefer_log < 16u) { + prefer_log++; + pr_info("vgsp-gr: MME-CARRY-SAVE-PREFER keep=draw-ia " + "h=0x%x old_win=%u new_win=%u\n", + old_h, old_win, win_n); + } + return; + } + if (draw_ia && prefer_log < 16u) { + prefer_log++; + pr_info("vgsp-gr: MME-CARRY-SAVE-PREFER take=draw-ia h=0x%x win=%u\n", + req->h_object, win_n); + } + pr_info("vgsp-gr: MME-CARRY-SAVE h=0x%x win=%u held=%u draw_ia=%u " + "raw=%u push=0x%llx\n", + req->h_object, win_n, held, draw_ia, req->stream_n, (unsigned long long)req->push_va); } |
