summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c348
1 files changed, 289 insertions, 59 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 94b0cae..5c36c35 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -6163,10 +6163,13 @@ static u32 *gsp_phys_rmcall_push(u32 *p, u32 method, u32 data)
* (channel_utils.c:812-820). Returns the block size in dwords (13 method
* pairs = 26 dwords, <= GPFIFO entry LENGTH field, bits 30:10). The ladder
* stage-4 call passes GSP_PHYS_RMCALL_COPY_SIZE; the P5 shadow submit passes
- * the caller's size (both within one 4 KB ladder page).
+ * the caller's size (both within one 4 KB ladder page). P6c: sem_payload is
+ * the value the release writes; every legacy call site passes
+ * GSP_PHYS_RMCALL_SEM_PAYLOAD so the block is byte-identical to before.
*/
static u32 gsp_phys_rmcall_build_methods(u32 *pb, u64 sem_va, u64 src_va,
- u64 dst_va, u32 bytes)
+ u64 dst_va, u32 bytes,
+ u32 sem_payload)
{
u32 *p = pb;
@@ -6177,7 +6180,7 @@ static u32 gsp_phys_rmcall_build_methods(u32 *pb, u64 sem_va, u64 src_va,
p = gsp_phys_rmcall_push(p, GSP_PHYS_RMCALL_CE_SET_SEMAPHORE_B,
(u32)sem_va);
p = gsp_phys_rmcall_push(p, GSP_PHYS_RMCALL_CE_SET_SEMAPHORE_PAYLOAD,
- GSP_PHYS_RMCALL_SEM_PAYLOAD);
+ sem_payload);
p = gsp_phys_rmcall_push(p, GSP_PHYS_RMCALL_CE_OFFSET_OUT_UPPER,
(u32)(dst_va >> 32));
p = gsp_phys_rmcall_push(p, GSP_PHYS_RMCALL_CE_OFFSET_OUT_LOWER,
@@ -6225,9 +6228,14 @@ struct gsp_phys_rmcall_ce_submit {
* refusal, BAR0 presence/length, GP_PUT bounds, GPFIFO GET encode and the
* token check. The semaphore is cleared before the doorbell so a stale release
* from a previous run cannot be observed as this submission's completion.
+ * P6c: sem_payload is the release value the method block carries; legacy
+ * callers pass GSP_PHYS_RMCALL_SEM_PAYLOAD. Note the module semaphore is
+ * still cleared even when the caller polls a guest page: the clear only
+ * guards the module-sem poll path and is a harmless non-guest write.
*/
static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
u64 dst_va, u64 sem_va, u32 bytes,
+ u32 sem_payload,
struct gsp_phys_rmcall_ce_submit *out)
{
struct gsp_phys_boot_chunk *pb =
@@ -6276,7 +6284,7 @@ static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
wmb();
words = gsp_phys_rmcall_build_methods(pb_va, sem_va, src_va, dst_va,
- bytes);
+ bytes, sem_payload);
gpput = get_unaligned_le32((u8 *)userd + GSP_PHYS_RMCALL_USERD_GPPUT_OFF);
gpget = get_unaligned_le32((u8 *)userd + GSP_PHYS_RMCALL_USERD_GPGET_OFF);
@@ -6376,7 +6384,9 @@ static int gsp_phys_rmcall_ce_copy_va(void __iomem *bar0, u64 src_va,
mutex_lock(&gsp_phys_rm_lock);
ret = gsp_phys_rmcall_ce_submit_locked(bar0, src_va, dst_va, sem_va,
- bytes, &sub);
+ bytes,
+ GSP_PHYS_RMCALL_SEM_PAYLOAD,
+ &sub);
mutex_unlock(&gsp_phys_rm_lock);
if (ret)
return ret;
@@ -6510,7 +6520,9 @@ int gsp_phys_backend_ce_copy_submit(u64 src_va, u64 dst_va, u64 sem_va,
return -EAGAIN;
}
ret = gsp_phys_rmcall_ce_submit_locked(bar0, src_va, dst_va, sem_va,
- bytes, &sub);
+ bytes,
+ GSP_PHYS_RMCALL_SEM_PAYLOAD,
+ &sub);
mutex_unlock(&gsp_phys_rm_lock);
if (ret) {
gsp_phys_work_refused++;
@@ -6625,6 +6637,39 @@ void gsp_phys_backend_guest_counters(u64 *ok, u64 *verify_ok, u64 *verify_fail,
EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_counters);
/*
+ * P6c relay-path counters. Only a copy submitted with a nonzero sem_hpa (the
+ * completion relay) moves these; every legacy call keeps moving the guest
+ * counters above only, so with gsp_phys_relay=0 they stay zero and the legacy
+ * lines are identical. Plain increments from the sema service work item; only
+ * logging and the debugfs state file read them.
+ */
+static u64 gsp_phys_relay_requested;
+static u64 gsp_phys_relay_ok;
+static u64 gsp_phys_relay_verify_fail;
+static u64 gsp_phys_relay_timed_out;
+static u64 gsp_phys_relay_refused;
+static u64 gsp_phys_relay_pool_exhausted;
+
+void gsp_phys_backend_relay_counters(u64 *requested, u64 *ok, u64 *verify_fail,
+ u64 *timeouts, u64 *refused,
+ u64 *pool_exhausted)
+{
+ if (requested)
+ *requested = gsp_phys_relay_requested;
+ if (ok)
+ *ok = gsp_phys_relay_ok;
+ if (verify_fail)
+ *verify_fail = gsp_phys_relay_verify_fail;
+ if (timeouts)
+ *timeouts = gsp_phys_relay_timed_out;
+ if (refused)
+ *refused = gsp_phys_relay_refused;
+ if (pool_exhausted)
+ *pool_exhausted = gsp_phys_relay_pool_exhausted;
+}
+EXPORT_SYMBOL_GPL(gsp_phys_backend_relay_counters);
+
+/*
* Allocate one fresh 128 B GMMU PTE fetch line from the guest scratch PT pool
* and write both operand PTEs into it (src at 16*line_in_page, dst at
* 16*line_in_page + 1). Called with gsp_phys_rm_lock held, so the monotonic
@@ -6637,9 +6682,15 @@ EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_counters);
* timed out with sem=0. The scratch PT pages were zeroed at stage 2, so every
* unconsumed slot holds an invalid PTE. Returns -ENOSPC when the pool is
* exhausted and -EIO when the scratch PT pages are not allocated.
+ *
+ * P6c relay: a nonzero sem_hpa additionally writes a third PTE at
+ * 16*line_in_page + 2 and returns sem_va = line_va + 2*PAGE_SIZE; sem_hpa==0
+ * writes nothing and returns sem_va=0. One line per relay copy either way, so
+ * the pool capacity (and its exhaustion behavior) is unchanged.
*/
static int gsp_phys_rmcall_guest_map_locked(u64 src_hpa, u64 dst_hpa,
- u64 *src_va, u64 *dst_va)
+ u64 sem_hpa, u64 *src_va,
+ u64 *dst_va, u64 *sem_va)
{
struct gsp_phys_boot_chunk *guest_pt_chunk;
u32 line = boot_stage.rmcall_guest_pt_next_line;
@@ -6670,11 +6721,21 @@ static int gsp_phys_rmcall_guest_map_locked(u64 src_hpa, u64 dst_hpa,
put_unaligned_le64(gsp_phys_rmcall_pte(dst_hpa),
pt + (size_t)(GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES *
line_in_page + 1) * 8);
+ /*
+ * P6c relay: the guest-visible semaphore page gets the third slot of
+ * the same never-reused line; the write is ordered with the other two
+ * by the dma_wmb() below, before any doorbell.
+ */
+ if (sem_hpa)
+ put_unaligned_le64(gsp_phys_rmcall_pte(sem_hpa),
+ pt + (size_t)(GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES *
+ line_in_page + 2) * 8);
dma_wmb();
boot_stage.rmcall_guest_pt_next_line = line + 1;
*src_va = va;
*dst_va = va + GSP_PHYS_PAGE_SIZE;
+ *sem_va = sem_hpa ? va + 2 * GSP_PHYS_PAGE_SIZE : 0;
return 0;
}
@@ -6688,39 +6749,73 @@ static int gsp_phys_rmcall_guest_map_locked(u64 src_hpa, u64 dst_hpa,
* gsp_phys_work_forward requirement, so the P6a triggers can share the same
* fresh-line copy path with forwarding. *sem_out receives the last
* semaphore word seen on success or timeout.
+ *
+ * P6c completion relay: a nonzero sem_hpa adds a third PTE on the same fresh
+ * line for the guest-visible semaphore page (pinned with pfn_valid ->
+ * get_page/put_page for the duration), points the CE release methods at
+ * sem_va + sem_off with sem_payload and polls the guest-visible word at
+ * __va(sem_hpa) + sem_off for the exact payload instead of the module
+ * semaphore. A zero sem_hpa keeps the module-semaphore behavior
+ * byte-identical (same gates, same counters, same logs). Relay refusals,
+ * timeouts and verify failures move the relay counters and return an errno
+ * the caller falls back to, so no release can be lost. *out (if given)
+ * always receives the last semaphore word, the elapsed milliseconds and the
+ * return code.
*/
static int gsp_phys_guest_ce_copy_common(u64 src_hpa, u32 src_off, u64 dst_hpa,
u32 dst_off, u32 bytes, u32 poll_ms,
- bool need_work_forward, u32 *sem_out)
+ bool need_work_forward,
+ u64 sem_hpa, u32 sem_off,
+ u32 sem_payload,
+ struct gsp_phys_backend_copy_result *out,
+ u32 *sem_out)
{
struct gsp_phys_boot_chunk *sem =
&boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_SEM];
void __iomem *bar0;
+ struct page *sem_page = NULL;
+ unsigned long start = jiffies;
unsigned long deadline;
- u64 src_va = 0, dst_va = 0;
+ u64 src_va = 0, dst_va = 0, sem_va = 0;
u32 poll = 0;
+ bool relay = sem_hpa != 0;
int ret;
+ if (relay)
+ gsp_phys_relay_requested++;
+
/*
* Every gate is fail-closed: the sema service's ladder fallback keeps
* the software release authoritative, so a refusal never loses work.
*/
if (need_work_forward) {
if (!gsp_phys_backend_work_ready()) {
- gsp_phys_guest_refused++;
- return -EAGAIN;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
+ ret = -EAGAIN;
+ goto out;
}
} else {
if (!gsp_phys_backend_ladder_ready()) {
- gsp_phys_guest_refused++;
- return -EAGAIN;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
+ ret = -EAGAIN;
+ goto out;
}
}
if (!gsp_phys_guest_mem_enabled() ||
gsp_phys_dma_domain_identity() != 1 ||
!gsp_phys_guest_ram_active()) {
- gsp_phys_guest_refused++;
- return -EAGAIN;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
+ ret = -EAGAIN;
+ goto out;
}
if (!src_hpa || !dst_hpa ||
!IS_ALIGNED(src_hpa, GSP_PHYS_PAGE_SIZE) ||
@@ -6732,15 +6827,42 @@ static int gsp_phys_guest_ce_copy_common(u64 src_hpa, u32 src_off, u64 dst_hpa,
pr_err("gsp-phys-work: GUEST CE COPY FAILED: invalid operands src_hpa=0x%llx src_off=%u dst_hpa=0x%llx dst_off=%u bytes=%u (want page-aligned HPAs, 4..%u bytes, 4-aligned, in-page)\n",
src_hpa, src_off, dst_hpa, dst_off, bytes,
GSP_PHYS_RMCALL_COPY_SIZE);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
+ }
+ if (relay &&
+ (!IS_ALIGNED(sem_hpa, GSP_PHYS_PAGE_SIZE) ||
+ (u64)sem_off + 4 > bytes || !sem_payload)) {
+ gsp_phys_relay_refused++;
+ pr_err("gsp-phys-work: GUEST CE RELAY FAILED: invalid semaphore relay sem_hpa=0x%llx sem_off=%u sem_payload=0x%08x bytes=%u (want a page-aligned HPA, sem_off+4 <= copy size, nonzero payload)\n",
+ sem_hpa, sem_off, sem_payload, bytes);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (relay) {
+ unsigned long pfn = sem_hpa >> PAGE_SHIFT;
+
+ if (!pfn_valid(pfn)) {
+ gsp_phys_relay_refused++;
+ pr_err("gsp-phys-work: GUEST CE RELAY FAILED: semaphore HPA 0x%llx is not a valid RAM page\n",
+ sem_hpa);
+ ret = -EINVAL;
+ goto out;
+ }
+ sem_page = pfn_to_page(pfn);
+ get_page(sem_page);
}
if (poll_ms > GSP_PHYS_BACKEND_WORK_POLL_MAX_MS)
poll_ms = GSP_PHYS_BACKEND_WORK_POLL_MAX_MS;
bar0 = gsp_phys_gpu_bar0();
if (!bar0) {
- gsp_phys_guest_refused++;
- return -EAGAIN;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
+ ret = -EAGAIN;
+ goto out;
}
mutex_lock(&gsp_phys_rm_lock);
@@ -6753,64 +6875,104 @@ static int gsp_phys_guest_ce_copy_common(u64 src_hpa, u32 src_off, u64 dst_hpa,
boot_stage.rm_unload_submitted || !boot_stage.rmcall_channel ||
boot_stage.rmcall_channel_server_mem || !boot_stage.rmcall_token) {
mutex_unlock(&gsp_phys_rm_lock);
- gsp_phys_guest_refused++;
- return -EAGAIN;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
+ ret = -EAGAIN;
+ goto out;
}
- ret = gsp_phys_rmcall_guest_map_locked(src_hpa, dst_hpa, &src_va,
- &dst_va);
+ ret = gsp_phys_rmcall_guest_map_locked(src_hpa, dst_hpa,
+ relay ? sem_hpa : 0, &src_va,
+ &dst_va, &sem_va);
if (ret) {
if (ret == -ENOSPC) {
- gsp_phys_guest_pool_exhausted++;
- if ((gsp_phys_guest_pool_exhausted & 63) == 1)
- pr_err("gsp-phys-work: GUEST CE COPY FAILED: scratch-PT pool exhausted (no line reuse) pool_exhausted=%llu capacity=%u; falling back to the ladder path\n",
- gsp_phys_guest_pool_exhausted,
- GSP_PHYS_RMCALL_GUEST_PT_PAGES *
- GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE);
+ if (relay) {
+ gsp_phys_relay_pool_exhausted++;
+ if ((gsp_phys_relay_pool_exhausted & 63) == 1)
+ pr_err("gsp-phys-work: GUEST CE RELAY FAILED: scratch-PT pool exhausted (no line reuse) pool_exhausted=%llu capacity=%u; falling back to the software release\n",
+ gsp_phys_relay_pool_exhausted,
+ GSP_PHYS_RMCALL_GUEST_PT_PAGES *
+ GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE);
+ } else {
+ gsp_phys_guest_pool_exhausted++;
+ if ((gsp_phys_guest_pool_exhausted & 63) == 1)
+ pr_err("gsp-phys-work: GUEST CE COPY FAILED: scratch-PT pool exhausted (no line reuse) pool_exhausted=%llu capacity=%u; falling back to the ladder path\n",
+ gsp_phys_guest_pool_exhausted,
+ GSP_PHYS_RMCALL_GUEST_PT_PAGES *
+ GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE);
+ }
} else {
- gsp_phys_guest_refused++;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
pr_err("gsp-phys-work: GUEST CE COPY FAILED: scratch PT not usable (%d) src_hpa=0x%llx dst_hpa=0x%llx\n",
ret, src_hpa, dst_hpa);
}
mutex_unlock(&gsp_phys_rm_lock);
- return ret;
+ goto out;
}
/*
* The scratch PTEs map whole pages, so fold each operand's in-page
* offset into the submitted VAs; the verify below uses the same
- * offsets, keeping the transfer and the check consistent.
+ * offsets, keeping the transfer and the check consistent. The relay
+ * points the release at the guest semaphore PTE at sem_va + sem_off
+ * and carries the caller's payload.
*/
ret = gsp_phys_rmcall_ce_submit_locked(bar0, src_va + src_off,
dst_va + dst_off,
- GSP_PHYS_RMCALL_VA_SEM, bytes,
+ relay ? sem_va + sem_off :
+ GSP_PHYS_RMCALL_VA_SEM,
+ bytes,
+ relay ? sem_payload :
+ GSP_PHYS_RMCALL_SEM_PAYLOAD,
NULL);
mutex_unlock(&gsp_phys_rm_lock);
if (ret) {
- gsp_phys_guest_refused++;
+ if (relay)
+ gsp_phys_relay_refused++;
+ else
+ gsp_phys_guest_refused++;
pr_err("gsp-phys-work: GUEST CE COPY FAILED: submit refused (%d) src_hpa=0x%llx dst_hpa=0x%llx bytes=%u\n",
ret, src_hpa, dst_hpa, bytes);
- return ret;
+ goto out;
}
/*
- * Poll the module semaphore WITHOUT gsp_phys_rm_lock (same discipline
- * as the P5 path): the release is written by the engine, so no host
- * path can race it and holding the lock would stall the RPC path.
+ * Poll the release WITHOUT gsp_phys_rm_lock (same discipline as the
+ * P5 path): the release is written by the engine, so no host path can
+ * race it and holding the lock would stall the RPC path. The relay
+ * watches the guest-visible word through its pin/direct map; the
+ * legacy path polls the module ladder semaphore exactly as before.
*/
deadline = jiffies + msecs_to_jiffies(poll_ms);
for (;;) {
- poll = READ_ONCE(*(u32 *)gsp_phys_chunk_page_va(sem, 0));
- if (poll == GSP_PHYS_RMCALL_SEM_PAYLOAD)
+ if (relay)
+ poll = READ_ONCE(*(u32 *)((u8 *)__va(sem_hpa) + sem_off));
+ else
+ poll = READ_ONCE(*(u32 *)gsp_phys_chunk_page_va(sem, 0));
+ if (poll == (relay ? sem_payload : GSP_PHYS_RMCALL_SEM_PAYLOAD))
break;
if (time_after_eq(jiffies, deadline)) {
- gsp_phys_guest_refused++;
+ if (relay) {
+ gsp_phys_relay_timed_out++;
+ pr_err("gsp-phys-work: GUEST CE RELAY FAILED: timeout after %u ms (guest sem=0x%08x want=0x%08x) sem_hpa=0x%llx+%u src_hpa=0x%llx dst_hpa=0x%llx bytes=%u\n",
+ poll_ms, poll, sem_payload, sem_hpa,
+ sem_off, src_hpa, dst_hpa, bytes);
+ } else {
+ gsp_phys_guest_refused++;
+ pr_err("gsp-phys-work: GUEST CE COPY FAILED: timeout after %u ms (sem=0x%08x want=0x%08x) src_hpa=0x%llx dst_hpa=0x%llx bytes=%u\n",
+ poll_ms, poll,
+ GSP_PHYS_RMCALL_SEM_PAYLOAD,
+ src_hpa, dst_hpa, bytes);
+ }
if (sem_out)
*sem_out = poll;
- pr_err("gsp-phys-work: GUEST CE COPY FAILED: timeout after %u ms (sem=0x%08x want=0x%08x) src_hpa=0x%llx dst_hpa=0x%llx bytes=%u\n",
- poll_ms, poll, GSP_PHYS_RMCALL_SEM_PAYLOAD,
- src_hpa, dst_hpa, bytes);
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto out;
}
msleep(GSP_PHYS_RMCALL_POLL_MS);
}
@@ -6822,28 +6984,70 @@ static int gsp_phys_guest_ce_copy_common(u64 src_hpa, u32 src_off, u64 dst_hpa,
*/
if (memcmp((u8 *)__va(dst_hpa) + dst_off,
(u8 *)__va(src_hpa) + src_off, bytes) != 0) {
- gsp_phys_guest_verify_fail++;
- pr_err("gsp-phys-work: GUEST CE COPY FAILED: semaphore released (sem=0x%08x) but HPA dst 0x%llx+%u does not match src 0x%llx+%u after %u bytes\n",
- poll, dst_hpa, dst_off, src_hpa, src_off, bytes);
- return -EIO;
+ if (relay) {
+ gsp_phys_relay_verify_fail++;
+ pr_err("gsp-phys-work: GUEST CE RELAY FAILED: semaphore released (sem=0x%08x) but HPA dst 0x%llx+%u does not match src 0x%llx+%u after %u bytes\n",
+ poll, dst_hpa, dst_off, src_hpa, src_off,
+ bytes);
+ } else {
+ gsp_phys_guest_verify_fail++;
+ pr_err("gsp-phys-work: GUEST CE COPY FAILED: semaphore released (sem=0x%08x) but HPA dst 0x%llx+%u does not match src 0x%llx+%u after %u bytes\n",
+ poll, dst_hpa, dst_off, src_hpa, src_off,
+ bytes);
+ }
+ ret = -EIO;
+ goto out;
}
- gsp_phys_guest_verify_ok++;
- gsp_phys_guest_fwd_ok++;
if (sem_out)
*sem_out = poll;
- if (gsp_phys_guest_fwd_ok == 1 || (gsp_phys_guest_fwd_ok & 63) == 0)
- pr_info("gsp-phys-work: GUEST CE COPY OK src_hpa=0x%llx dst_hpa=0x%llx bytes=%u sem=0x%08x verify_ok=1 copied=%llu\n",
- src_hpa, dst_hpa, bytes, poll,
- gsp_phys_guest_fwd_ok);
- return 0;
+ if (relay) {
+ gsp_phys_relay_ok++;
+ if (gsp_phys_relay_ok == 1 || (gsp_phys_relay_ok & 63) == 0)
+ pr_info("gsp-phys-work: GUEST CE RELAY OK src_hpa=0x%llx dst_hpa=0x%llx bytes=%u sem_hpa=0x%llx+%u sem=0x%08x relays=%llu\n",
+ src_hpa, dst_hpa, bytes, sem_hpa, sem_off,
+ poll, gsp_phys_relay_ok);
+ } else {
+ gsp_phys_guest_verify_ok++;
+ gsp_phys_guest_fwd_ok++;
+ if (gsp_phys_guest_fwd_ok == 1 ||
+ (gsp_phys_guest_fwd_ok & 63) == 0)
+ pr_info("gsp-phys-work: GUEST CE COPY OK src_hpa=0x%llx dst_hpa=0x%llx bytes=%u sem=0x%08x verify_ok=1 copied=%llu\n",
+ src_hpa, dst_hpa, bytes, poll,
+ gsp_phys_guest_fwd_ok);
+ }
+ ret = 0;
+
+out:
+ if (sem_page)
+ put_page(sem_page);
+ if (out) {
+ out->sem_value = poll;
+ out->elapsed_ms = jiffies_to_msecs(jiffies - start);
+ out->rc = ret;
+ }
+ return ret;
+}
+
+int gsp_phys_backend_guest_ce_copy_ex(u64 src_hpa, u32 src_off, u64 dst_hpa,
+ u32 dst_off, u32 bytes, u32 poll_ms,
+ u64 sem_hpa, u32 sem_off,
+ u32 sem_payload,
+ struct gsp_phys_backend_copy_result *out)
+{
+ return gsp_phys_guest_ce_copy_common(src_hpa, src_off, dst_hpa, dst_off,
+ bytes, poll_ms, true,
+ sem_hpa, sem_off, sem_payload,
+ out, NULL);
}
+EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_ce_copy_ex);
int gsp_phys_backend_guest_ce_copy(u64 src_hpa, u32 src_off, u64 dst_hpa,
u32 dst_off, u32 bytes, u32 poll_ms)
{
- return gsp_phys_guest_ce_copy_common(src_hpa, src_off, dst_hpa, dst_off,
- bytes, poll_ms, true, NULL);
+ return gsp_phys_backend_guest_ce_copy_ex(src_hpa, src_off, dst_hpa,
+ dst_off, bytes, poll_ms,
+ 0, 0, 0, NULL);
}
EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_ce_copy);
@@ -6861,7 +7065,8 @@ static int gsp_phys_backend_guest_ce_copy_trigger(u64 src_hpa, u32 src_off,
u32 *sem_out)
{
return gsp_phys_guest_ce_copy_common(src_hpa, src_off, dst_hpa, dst_off,
- bytes, poll_ms, false, sem_out);
+ bytes, poll_ms, false,
+ 0, 0, 0, NULL, sem_out);
}
/*
@@ -7043,7 +7248,9 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0)
ret = gsp_phys_rmcall_ce_submit_locked(bar0, GSP_PHYS_RMCALL_VA_SRC,
GSP_PHYS_RMCALL_VA_DST,
GSP_PHYS_RMCALL_VA_SEM,
- GSP_PHYS_RMCALL_COPY_SIZE, &sub);
+ GSP_PHYS_RMCALL_COPY_SIZE,
+ GSP_PHYS_RMCALL_SEM_PAYLOAD,
+ &sub);
if (ret) {
pr_err("gsp-phys-boot: rm-call: stage 4 aborted before the doorbell: submission refused (%d)\n",
ret);
@@ -7691,6 +7898,29 @@ static int gsp_phys_state_show(struct seq_file *m, void *v)
gsp_phys_work_hw_primary_enabled());
}
{
+ /*
+ * P6c completion relay: the sema service's relay-selection and
+ * hold-verification counters (requested/ok/fallback/skipped_sw/
+ * verify_fail/resolve_fail) plus the booter relay copy
+ * counters (timeouts/pool_exhausted/refused) and the parameter
+ * state. All zero while the relay is off.
+ */
+ u64 r_req = 0, r_ok = 0, r_fallback = 0, r_skipped = 0;
+ u64 r_verify_fail = 0, r_resolve_fail = 0;
+ u64 r_timeouts = 0, r_pool = 0, r_refused = 0;
+
+ gsp_sema_service_fwd_relay_stats(&r_req, &r_ok, &r_fallback,
+ &r_skipped, &r_verify_fail,
+ &r_resolve_fail);
+ gsp_phys_backend_relay_counters(NULL, NULL, NULL, &r_timeouts,
+ &r_refused, &r_pool);
+ seq_printf(m,
+ "work_relay: requested=%llu ok=%llu fallback=%llu skipped_sw=%llu verify_fail=%llu resolve_fail=%llu timeouts=%llu pool_exhausted=%llu refused=%llu relay_param=%u\n",
+ r_req, r_ok, r_fallback, r_skipped, r_verify_fail,
+ r_resolve_fail, r_timeouts, r_pool, r_refused,
+ gsp_phys_relay_enabled());
+ }
+ {
char guest_ram[512];
gsp_phys_guest_ram_state(guest_ram, sizeof(guest_ram));