commit 0328e61d09adebd86db3b30c9b084556890241de
Author: XXX
Date: Wed Jul 31 12:41:12 2024 +0800
drm/xdxgpu/gfx: refine the codes of command kick
By default, ccb buffers are allocated in local video memory, refine
codes to make sure the ccb write complete before MTS kick
Signed-off-by: Yajun Li <yajun.li@xdxct.com>
Change-Id: I58e741f5ecc8b5cd5dbfcbb0c14636d39ba8d75f
diff --git a/xdxgpu/gfx/include/osfunc_common.h b/xdxgpu/gfx/include/osfunc_common.h
index 3a6158cc6..5d110b7e3 100755
--- a/xdxgpu/gfx/include/osfunc_common.h
+++ b/xdxgpu/gfx/include/osfunc_common.h
@@ -229,7 +229,10 @@ size_t StringLCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, size_t uDataSize);
if ((c) != 0U) \
{ \
(void) memset((a), (b), (c)); \
- OSWriteMemoryBarrier(a); \
+ if ((c) > 4) \
+ OSWriteMemoryBarrier((IMG_BYTE*)(a) + (c) - 4); \
+ else \
+ OSWriteMemoryBarrier((a)); \
} \
} while (false)
/**************************************************************************/ /*!
@@ -249,7 +252,10 @@ size_t StringLCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc, size_t uDataSize);
if ((c) != 0U) \
{ \
(void) memcpy((a), (b), (c)); \
- OSWriteMemoryBarrier(a); \
+ if ((c) > 4) \
+ OSWriteMemoryBarrier((IMG_BYTE*)(a) + (c) - 4); \
+ else \
+ OSWriteMemoryBarrier((a)); \
} \
} while (false)
#endif /* defined(__KERNEL__) */
diff --git a/xdxgpu/gfx/services/server/devices/volcanic/rgxfwutils.c b/xdxgpu/gfx/services/server/devices/volcanic/rgxfwutils.c
index e6f1627ea..1934f034e 100644
--- a/xdxgpu/gfx/services/server/devices/volcanic/rgxfwutils.c
+++ b/xdxgpu/gfx/services/server/devices/volcanic/rgxfwutils.c
@@ -263,6 +263,13 @@ static void _FreeSLC3Fence(PVRSRV_RGXDEV_INFO* psDevInfo)
static void __MTSScheduleWrite(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Value)
{
+#ifdef XDXGPU
+ /* Ensure any uncached/WC memory writes are flushed from CPU write buffers
+ * before kicking MTS.
+ */
+ OSWriteMemoryBarrier(NULL);
+#endif
+
/* This should *NOT* happen. Try to trace what caused this and avoid a NPE
* with the Write/Read at the foot of the function.
*/
@@ -282,6 +289,7 @@ static void __MTSScheduleWrite(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Val
(void) OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_MTS_SCHEDULE);
}
+
/*************************************************************************/ /*!
@Function RGXSetupFwAllocation
@@ -3960,7 +3968,6 @@ static PVRSRV_ERROR RGXSendCommandRaw(PVRSRV_RGXDEV_INFO *psDevInfo,
OSCachedMemCopy(&pui8KCCB[ui32OldWriteOffset * sizeof(RGXFWIF_KCCB_CMD)],
psKCCBCmd, ui32CmdMemCopySize);
#endif
-
RGXFwSharedMemCacheOpExec(&pui8KCCB[ui32OldWriteOffset * sizeof(RGXFWIF_KCCB_CMD)], ui32CmdMemCopySize, PVRSRV_CACHE_OP_FLUSH);
/* If non-NULL pui32CmdKCCBSlot passed-in, return the kCCB slot in which the command was enqueued */
@@ -3986,6 +3993,10 @@ static PVRSRV_ERROR RGXSendCommandRaw(PVRSRV_RGXDEV_INFO *psDevInfo,
__func__, psDevInfo, ui32OldWriteOffset, RGXFWIF_KCCB_RTN_SLOT_NO_RESPONSE, psKCCBCmd->eCmdType));
}
+#ifdef XDXGPU
+ (void) (*(volatile IMG_UINT32 *)(&pui8KCCB[ui32OldWriteOffset * sizeof(RGXFWIF_KCCB_CMD) + ui32CmdMemCopySize - 4]));
+#endif
+
/* Memory barrier before KCCB write offset update. */
OSWriteMemoryBarrier(NULL);
下面是对 该 patch 的全部技术作用与背景 的逐条深入分析,包括:
-
为什么要改
-
改了哪些路径
-
其在 PowerVR 架构(特别是 KCCB / MTS / WC uncached VRAM)的实际影响
-
为什么要读回最后 4 字节
-
如何与 DMA、SMMU、FreeList 等问题相关
🔎 总览:这个 patch 的核心目的
确保 KCCB / CCB 等命令 buffer 写入“真的”落到 GPU 可见的内存中,再进行 MTS Kick(即触发 Firmware 读取命令)。 解决 WC/Uncached/VRAM 写入延迟导致 GPU 读取到半写入指令的问题。
在 Imagination GPU 中,KCCB(Kernel CCB)写入后必须保证可见性,否则 FW 会读到断裂或未完成的命令 → TA/3D 卡死、无法上电、HWR 频繁。
patch 的动作本质上:
-
增强写屏障(memory barrier)
-
补充了一次读回(last dword readback) 来 flush WC buffer
-
确保 MTS kick 前保证 command buffer 的内存一致性
-
对写入地址做特定对齐/最后字取 flush
这些都是为了解决:
- ✔ VRAM / WC (Write Combine) 回写延迟
- ✔ Command queue 在 DMA/SMMU 之前未完全可见
- ✔ GPU firmware 读取“半写入” command 的风险
📌 第一部分:OSCachedMemSet / OSCachedMemCopy 的修改
patch:
if ((c) > 4)
OSWriteMemoryBarrier((IMG_BYTE*)(a) + (c) - 4);
else
OSWriteMemoryBarrier((a));
🧠 原因:WRITECOMBINE 区域的 flush 必须落在最后写入字附近
这是 Intel/ARM CPU 写合并区(WC) 的通用特性:
WC buffer 以 cacheline 为粒度(通常 32/64 字节)
OSWriteMemoryBarrier(addr) 通常实现为 sfence + 指定地址的 load/store
如果 barrier 错误地指向结构开头,而写的关键部分在最后几个字节, CPU 可能不会刷新最后部分
因此:
Barrier 指向最后 4 字节,确保之前的 WC 合并缓冲全部被 flush。
这是非常典型的 GPU MMIO/WC buffer 编程技巧。
📌 第二部分:__MTSScheduleWrite 之前加入 OSWriteMemoryBarrier(NULL)
#ifdef XDXGPU
OSWriteMemoryBarrier(NULL);
#endif
🧠 作用:在执行 MTS Kick 前全局 sfence,强制 flush 所有 WC 写
MTS Kick 是 GPU firmware 的调度触发点:
-
你写完 KCCB
-
你 kick MTS
-
GPU FW 立刻尝试从 KCCB 读取命令
如果 WC buffer 未 flush:
- KCCB 数据不完整 → FW 错误解析 → 卡死/HWR
这个 barrier 的加入确保:
kick 前所有指向 VRAM / Uncached 的 command buffer 都已落地,不会有半写情况。
📌 第三部分:KCCB 写入后加 readback(最关键的 patch)
代码:
#ifdef XDXGPU
(void)(*(volatile IMG_UINT32 *)(
&pui8KCCB[offset + size - 4]));
#endif
🧠 目的: 强制 CPU 从 WC buffer 提前 flush 写入
这是一条经典手段:
对刚写完的内存进行一次 volatile read,会强制 CPU 将 pending WC buffer 全部回写到 DRAM/VRAM。
CPU 原理:
-
WC buffer 的 flush 时机是松散的(lazy writeback)
-
但一旦对这个区域执行 Load 操作,需要确保 Load 是正确数据
-
因此 CPU 必须执行 flush,将合并写全部推入 memory
因此这是一个:
✔ 强制落地(强制同步)的 read barrier ✔ 明显比 OSWriteMemoryBarrier 还要强 ✔ 必须对 buffer 最后的字节读,确保整个写集合 flush ✔ 最常见于 GPU/Linux DMA 驱动
这种技巧你一般会在 AMD/NVIDIA/Intel 的 DMA ring buffer 写入中看到。
📌 第四部分:为什么加在这里?(KCCB → RGXSendCommandRaw)
PowerVR 的 KCCB 是 CPU → Firmware 的命令队列:
流程:
-
CPU 写入 KCCB entry
-
Flush cache / WC
-
Update write offset
-
Kick MTS → Firmware 读取并执行
任何 flush 漏掉会导致:
-
Firmware 读到脏数据
-
Command buffer stride 错乱
-
Firmware 解析失败 → 死循环
-
可能触发 HWR(你日志里常见)
patch 正是补上 flush 步骤。
📌 第五部分:为什么 patch 能大大降低 TA/3D 卡死、FreeList 错误、SMMU Page Fault?
因为KCCB 是 TA / 3D 的所有命令来源。
如果 KCCB 有问题:
-
TA Kick 信息错误 → TA 卡住
-
Page Table Sync 命令缺失 → SMMU miss
-
FreeList 更新命令丢失 → FreeList slice 不增 → 分配失败
-
3D CCB Kick 丢失 → 3D 阶段 stall → HWR
这些都是你近期日志出现的问题。
你的 patch 实际是在修复:
根因:VRAM/WC 写入未同步导致的命令队列不一致性。
📌 补充:为何 VRAM / Uncached 区域更容易出问题?
因为:
-
GPU 的 command buffer 不在 normal cached 内存中(通常 WC or Uncached)
-
CPU 写入这类区域不会立即真正写入内存,而是在缓冲区堆积
-
MTS Kick 立即触发 GPU FW 读取,但写入可能还没落地
所以你的命令可能变成:
-
前半写好了
-
后半还在 WC buffer
-
GPU FW 读取时 data torn → 卡死
🧩 最终总结:patch 的作用(一句话)
强制 CPU 完整刷新 KCCB/CCB 等命令 buffer 到 VRAM,使 GPU Firmware 不会读取到半写或未完成数据,确保命令一致性,避免卡死、HWR、FreeList 错误和 TA/3D 异常。
JINHU