#include "resman.h"
#include "bridged_support.h"
-#include "pdump_km.h"
+#include "pvr_pdump.h"
#include "ra.h"
#include "mmu.h"
#include "mm.h"
#include "pvrversion.h"
#include "sgx_options.h"
+#include "pvr_trace_cmd.h"
+
#ifdef CONFIG_DEBUG_FS
#include "pvr_debugfs.h"
#endif
psDevInfo->psKernelHWPerfCBMemInfo =
(struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWPerfCBMemInfo;
+#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
psDevInfo->psKernelEDMStatusBufferMemInfo =
- psInitInfo->hKernelEDMStatusBufferMemInfo;
+ (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->
+ hKernelEDMStatusBufferMemInfo;
+#endif
eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(struct PVRSRV_SGX_CCB_INFO),
ui32PC < ui32NumInitCommands; ui32PC++, psComm++) {
switch (psComm->eOp) {
case SGX_INIT_OP_WRITE_HW_REG:
- {
- OSWriteHWReg(psDevInfo->pvRegsBaseKM,
- psComm->sWriteHWReg.ui32Offset,
- psComm->sWriteHWReg.ui32Value);
- PDUMPREG(psComm->sWriteHWReg.ui32Offset,
- psComm->sWriteHWReg.ui32Value);
- break;
+ OSWriteHWReg(psDevInfo->pvRegsBaseKM,
+ psComm->sWriteHWReg.ui32Offset,
+ psComm->sWriteHWReg.ui32Value);
+ PDUMPREG(psComm->sWriteHWReg.ui32Offset,
+ psComm->sWriteHWReg.ui32Value);
+ break;
+ case SGX_INIT_OP_HALT:
+ /* Old OP_PDUMP_HW_REG masked OP_HALT */
+ if (psComm->sWriteHWReg.ui32Offset) {
+ pr_warning("%s: Init Script HALT command "
+ "contains data!\n", __func__);
+ pr_warning("PVR: Is userspace built with "
+ "incompatible PDUMP support?\n");
}
-#if defined(PDUMP)
+ return PVRSRV_OK;
case SGX_INIT_OP_PDUMP_HW_REG:
- {
- PDUMPREG(psComm->sPDumpHWReg.ui32Offset,
- psComm->sPDumpHWReg.ui32Value);
- break;
- }
-#endif
- case SGX_INIT_OP_HALT:
- {
- return PVRSRV_OK;
+#if defined(PDUMP)
+ if (!psComm->sPDumpHWReg.ui32Offset &&
+ !psComm->sPDumpHWReg.ui32Value) {
+ pr_warning("%s: Init Script PDUMP command "
+ "contains no offset/value!\n",
+ __func__);
+ pr_warning("PVR: Is userspace built without "
+ "PDUMP support?\n");
}
- case SGX_INIT_OP_ILLEGAL:
+ PDUMPREG(psComm->sPDumpHWReg.ui32Offset,
+ psComm->sPDumpHWReg.ui32Value);
+ break;
+#else
+ pr_err("%s: Init Script contains PDUMP writes!\n",
+ __func__);
+ pr_err("PVR: ERROR: Userspace built with PDUMP "
+ "support!\n");
+ return PVRSRV_ERROR_GENERIC;
+#endif /* PDUMP */
+ case SGX_INIT_OP_ILLEGAL:
default:
- {
- PVR_DPF(PVR_DBG_ERROR,
- "SGXRunScript: PC %d: Illegal command: %d",
- ui32PC, psComm->eOp);
- return PVRSRV_ERROR_GENERIC;
- }
+ pr_err("PVR: ERROR: %s: PC %d: Illegal operation: "
+ "0x%02X\n", __func__, ui32PC, psComm->eOp);
+ return PVRSRV_ERROR_GENERIC;
}
}
return proc_data;
}
-static void dump_process_info(struct PVRSRV_DEVICE_NODE *dev)
+static void pr_err_process_info(struct PVRSRV_PER_PROCESS_DATA *proc)
{
- struct PVRSRV_PER_PROCESS_DATA *proc;
-
- proc = find_cur_proc_data(dev);
-
- if (proc) {
- struct task_struct *tsk;
- int pid;
+ if (!proc)
+ return;
- pid = proc->ui32PID;
- rcu_read_lock();
- tsk = pid_task(find_vpid(pid), PIDTYPE_PID);
- pr_err("PID = %d, process name = %s\n", pid, tsk->comm);
- rcu_read_unlock();
- }
+ pr_err("PID = %d, process name = %s\n", proc->ui32PID, proc->name);
}
-static void dump_sgx_registers(struct PVRSRV_SGXDEV_INFO *psDevInfo)
+static void pr_err_sgx_registers(struct PVRSRV_SGXDEV_INFO *psDevInfo)
{
pr_err("EVENT_STATUS = 0x%08X\n"
"EVENT_STATUS2 = 0x%08X\n"
readl(psDevInfo->pvRegsBaseKM + EUR_CR_CLKGATECTL));
}
-#define BUF_DESC_CORRUPT (1 << 31)
-
-static void add_uniq_items(struct render_state_buf_list *dst,
- const struct render_state_buf_list *src)
-{
- int i;
-
- for (i = 0; i < src->cnt; i++) {
- const struct render_state_buf_info *sbinf = &src->info[i];
- int j;
-
- for (j = 0; j < dst->cnt; j++) {
- if (sbinf->buf_id == dst->info[j].buf_id) {
- if (memcmp(sbinf, &dst->info[j], sizeof(sbinf)))
- dst->info[j].type |= BUF_DESC_CORRUPT;
- break;
- }
- }
- if (j == dst->cnt) {
- /* Bound for cnt is guaranteed by the caller */
- dst->info[dst->cnt] = *sbinf;
- dst->cnt++;
- }
- }
-}
-
-static struct render_state_buf_list *create_merged_uniq_list(
- struct render_state_buf_list **bl_set, int set_size)
-{
- int i;
- struct render_state_buf_list *dbl;
- size_t size;
-
- /*
- * Create a buf list big enough to contain all elements from each
- * list in bl_set.
- */
- size = offsetof(struct render_state_buf_list, info[0]);
- for (i = 0; i < set_size; i++) {
- if (!bl_set[i])
- continue;
- size += bl_set[i]->cnt * sizeof(bl_set[i]->info[0]);
- }
- if (!size)
- return NULL;
- dbl = kmalloc(size, GFP_KERNEL);
- if (!dbl)
- return NULL;
-
- dbl->cnt = 0;
- for (i = 0; i < set_size; i++) {
- if (bl_set[i])
- add_uniq_items(dbl, bl_set[i]);
- }
-
- return dbl;
-}
-
-static void *vmap_buf(struct PVRSRV_PER_PROCESS_DATA *proc,
- u32 handle, off_t offset, size_t size)
-{
- struct PVRSRV_KERNEL_MEM_INFO *minfo;
- struct LinuxMemArea *mem_area;
- enum PVRSRV_ERROR err;
- unsigned start_ofs;
- unsigned end_ofs;
- int pg_cnt;
- struct page **pages;
- void *map;
- int i;
-
- if (offset & PAGE_MASK)
- return NULL;
-
- err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&minfo,
- (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
- if (err != PVRSRV_OK)
- return NULL;
- if (minfo->pvLinAddrKM)
- return minfo->pvLinAddrKM;
-
- err = PVRSRVLookupOSMemHandle(proc->psHandleBase, (void *)&mem_area,
- (void *)handle);
- if (err != PVRSRV_OK)
- return NULL;
-
- start_ofs = offset & PAGE_MASK;
- end_ofs = PAGE_ALIGN(offset + size);
- pg_cnt = (end_ofs - start_ofs) >> PAGE_SHIFT;
- pages = kmalloc(pg_cnt * sizeof(pages[0]), GFP_KERNEL);
- if (!pages)
- return NULL;
- for (i = 0; i < pg_cnt; i++) {
- unsigned pfn;
-
- pfn = LinuxMemAreaToCpuPFN(mem_area, start_ofs);
- if (!pfn_valid(pfn))
- goto err;
- pages[i] = pfn_to_page(pfn);
- start_ofs += PAGE_SIZE;
- }
- map = vmap(pages, pg_cnt, VM_MAP, PAGE_KERNEL);
- map += offset;
-err:
- kfree(pages);
-
- return map;
-}
-
-static void vunmap_buf(struct PVRSRV_PER_PROCESS_DATA *proc,
- u32 handle, void *map)
+#ifdef CONFIG_PVR_TRACE_CMD
+static void pr_err_cmd_trace(void)
{
- struct PVRSRV_KERNEL_MEM_INFO *minfo;
- enum PVRSRV_ERROR err;
-
- err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&minfo,
- (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
- if (err != PVRSRV_OK)
+ u8 *snapshot;
+ size_t snapshot_size;
+ loff_t snapshot_ofs;
+ char *str_buf;
+ size_t str_len;
+ int r;
+
+ str_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!str_buf) {
+ pr_err("%s: out of mem\n", __func__);
return;
- if (minfo->pvLinAddrKM)
- return;
- vunmap((void *)(((unsigned long)map) & PAGE_MASK));
-}
-
-static void dump_buf(void *start, size_t size, u32 type)
-{
- unsigned addr = 0;
- char *corr = "";
-
- if (type & BUF_DESC_CORRUPT) {
- type &= ~BUF_DESC_CORRUPT;
- corr = "(corrupt)";
- }
- printk(KERN_DEBUG "type %d%s size %d\n", type, corr, size);
- while (addr < size) {
- if (!(addr % 16)) {
- if (addr)
- printk("\n");
- printk(KERN_DEBUG "%08x ", addr);
- }
- printk("%08x ", *(u32 *)(start + addr));
- addr += 4;
}
- if (addr)
- printk("\n");
-}
-
-static struct render_state_buf_list *get_state_buf_list(
- struct PVRSRV_PER_PROCESS_DATA *proc,
- u32 handle, off_t offset)
-{
- struct PVRSRV_KERNEL_MEM_INFO *container;
- struct render_state_buf_list *buf;
- enum PVRSRV_ERROR err;
-
- err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&container,
- (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
- if (err != PVRSRV_OK)
- return NULL;
- if (!container->pvLinAddrKM)
- return NULL;
- if (offset + sizeof(*buf) > container->ui32AllocSize)
- return NULL;
- buf = container->pvLinAddrKM + offset;
-
- if (buf->cnt > ARRAY_SIZE(buf->info))
- return NULL;
+ pvr_trcmd_lock();
- return buf;
-}
-
-static void dump_state_buf_list(struct PVRSRV_PER_PROCESS_DATA *proc,
- struct render_state_buf_list *bl)
-{
- int i;
+ r = pvr_trcmd_create_snapshot(&snapshot, &snapshot_size);
+ if (r < 0) {
+ pvr_trcmd_unlock();
+ kfree(str_buf);
+ pr_err("%s: can't create snapshot (%d)\n", __func__, r);
- if (!bl->cnt)
return;
-
- printk(KERN_DEBUG "Dumping %d render state buffers\n", bl->cnt);
- for (i = 0; i < bl->cnt; i++) {
- struct render_state_buf_info *binfo;
- void *map;
-
- binfo = &bl->info[i];
-
- map = vmap_buf(proc, binfo->buf_id, binfo->offset, binfo->size);
- if (!map)
- continue;
- dump_buf(map, binfo->size, binfo->type);
-
- vunmap_buf(proc, binfo->buf_id, map);
}
-}
-static void dump_sgx_state_bufs(struct PVRSRV_DEVICE_NODE *dev_node)
-{
- struct PVRSRV_SGXDEV_INFO *dev_info = dev_node->pvDevice;
- struct SGXMKIF_HOST_CTL __iomem *hctl = dev_info->psSGXHostCtl;
- struct PVRSRV_PER_PROCESS_DATA *proc;
- struct render_state_buf_list *bl_set[2] = { NULL };
- struct render_state_buf_list *mbl;
- u32 handle_ta;
- u32 handle_3d;
+ pvr_trcmd_unlock();
- proc = find_cur_proc_data(dev_node);
- if (!proc)
- return;
-
- handle_ta = readl(&hctl->render_state_buf_ta_handle);
- handle_3d = readl(&hctl->render_state_buf_3d_handle);
- bl_set[0] = get_state_buf_list(proc, handle_ta,
- dev_info->state_buf_ofs);
- /*
- * The two buf list can be the same if the TA and 3D phases used the
- * same context at the time of the HWrec. In this case just ignore
- * one of them.
- */
- if (handle_ta != handle_3d)
- bl_set[1] = get_state_buf_list(proc, handle_3d,
- dev_info->state_buf_ofs);
- mbl = create_merged_uniq_list(bl_set, ARRAY_SIZE(bl_set));
- if (!mbl)
- return;
+ snapshot_ofs = 0;
+ do {
+ str_len = pvr_trcmd_print(str_buf, PAGE_SIZE, snapshot,
+ snapshot_size, &snapshot_ofs);
+ printk(KERN_DEBUG "%s", str_buf);
+ } while (str_len);
- dump_state_buf_list(proc, mbl);
- kfree(mbl);
+ pvr_trcmd_destroy_snapshot(snapshot);
+ kfree(str_buf);
}
+#endif
/* Should be called with pvr_lock held */
-void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode)
+void
+HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode, const char *caller)
{
enum PVRSRV_ERROR eError;
struct PVRSRV_SGXDEV_INFO *psDevInfo =
(struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
psDevInfo->psSGXHostCtl;
+ struct PVRSRV_PER_PROCESS_DATA *proc;
u32 l;
int max_retries = 10;
l |= PVRSRV_USSE_EDM_INTERRUPT_HWR;
writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
- pr_err("%s: SGX Hardware Recovery triggered\n", __func__);
+ pr_err("SGX Hardware Recovery triggered (from %s)\n", caller);
+
+ proc = find_cur_proc_data(psDeviceNode);
- dump_process_info(psDeviceNode);
- dump_sgx_registers(psDevInfo);
- dump_sgx_state_bufs(psDeviceNode);
+ pr_err_process_info(proc);
+ pr_err_sgx_registers(psDevInfo);
+#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
+ edm_trace_print(psDevInfo, NULL, 0);
+#endif
+#ifdef CONFIG_PVR_TRACE_CMD
+ pr_err_cmd_trace();
+#endif
#ifdef CONFIG_DEBUG_FS
- pvr_hwrec_dump(psDevInfo);
+ pvr_hwrec_dump(proc, psDevInfo);
#endif
PDUMPSUSPEND();
l++;
writel(l, &psSGXHostCtl->ui32HostDetectedLockups);
- HWRecoveryResetSGX(psDeviceNode);
+ HWRecoveryResetSGX(psDeviceNode, __func__);
pvr_dev_unlock();
}
if ((l1 & PVRSRV_USSE_EDM_INTERRUPT_HWR) &&
!(l2 & PVRSRV_USSE_EDM_INTERRUPT_HWR))
- HWRecoveryResetSGX(psDeviceNode);
+ HWRecoveryResetSGX(psDeviceNode, __func__);
if (psDeviceNode->bReProcessDeviceCommandComplete)
SGXScheduleProcessQueues(psDeviceNode);
if ((psSGXFeatures->ui32DDKVersion !=
((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) |
PVRVERSION_BRANCH)) ||
- (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD)) {
+ (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD &&
+ psSGXFeatures->ui32DDKBuild != 2616)) {
pr_err("pvr: incompatible driver DDK revision (%d)"
"/device DDK revision (%d).\n",
PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild);
opts = psSGXFeatures->ui32BuildOptions;
opt_mismatch = opts ^ SGX_BUILD_OPTIONS;
+#if 0
/* we support the ABIs both with and without EDM tracing option */
opt_mismatch &= ~PVRSRV_USSE_EDM_STATUS_DEBUG_SET_OFFSET;
+#endif
if (opt_mismatch) {
if (SGX_BUILD_OPTIONS & opt_mismatch)
pr_err("pvr: mismatch in driver and microkernel build "