#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"
+#ifdef CONFIG_DEBUG_FS
+#include "pvr_debugfs.h"
+#endif
+
static IMG_BOOL SGX_ISRHandler(void *pvData);
static u32 gui32EventStatusServicesByISR;
hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr,
NULL, NULL);
+ if (!hKernelDevMemContext)
+ goto err1;
psDevInfo->sKernelPDDevPAddr = sPDDevPAddr;
BM_CreateHeap(hKernelDevMemContext,
&psDeviceMemoryHeap[i]);
+ if (!hDevMemHeap)
+ goto err2;
+
psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap;
break;
}
if (eError != PVRSRV_OK) {
PVR_DPF(PVR_DBG_ERROR,
"DevInitSGX : Failed to alloc memory for BIF reset");
- return PVRSRV_ERROR_GENERIC;
+ goto err2;
}
return PVRSRV_OK;
+err2:
+ while (i) {
+ int type;
+
+ i--;
+ type = psDeviceMemoryHeap[i].DevMemHeapType;
+ if (type != DEVICE_MEMORY_HEAP_KERNEL &&
+ type != DEVICE_MEMORY_HEAP_SHARED &&
+ type != DEVICE_MEMORY_HEAP_SHARED_EXPORTED)
+ continue;
+ BM_DestroyHeap(psDeviceMemoryHeap[i].hDevMemHeap);
+ }
+ BM_DestroyContext(hKernelDevMemContext);
+err1:
+ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+ sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL);
+
+ return PVRSRV_ERROR_GENERIC;
}
enum PVRSRV_ERROR SGXGetInfoForSrvinitKM(void *hDevHandle,
return PVRSRV_OK;
}
-#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) || defined(CONFIG_DEBUG_FS)
-
-static size_t __print_edm_trace(struct PVRSRV_SGXDEV_INFO *sdev, char *dst,
- size_t dst_len)
-{
- u32 *buf_start;
- u32 *buf_end;
- u32 *buf;
- size_t p = 0;
- size_t wr_ofs;
- int i;
-
-#define _PR(fmt, ...) do { \
- if (dst) \
- p += snprintf(dst + p, dst_len - p, fmt, ## __VA_ARGS__); \
- else \
- printk(KERN_DEBUG fmt, ## __VA_ARGS__); \
-} while (0)
-
- if (!sdev->psKernelEDMStatusBufferMemInfo)
- return 0;
-
- buf = sdev->psKernelEDMStatusBufferMemInfo->pvLinAddrKM;
-
- _PR("Last SGX microkernel status code: 0x%x\n", *buf);
- buf++;
- wr_ofs = *buf;
- buf++;
-
- buf_start = buf;
- buf_end = buf + SGXMK_TRACE_BUFFER_SIZE * 4;
-
- buf += wr_ofs * 4;
-
- /* Dump the status values */
- for (i = 0; i < SGXMK_TRACE_BUFFER_SIZE; i++) {
- _PR("%3d %08X %08X %08X %08X\n",
- i, buf[2], buf[3], buf[1], buf[0]);
- buf += 4;
- if (buf >= buf_end)
- buf = buf_start;
- }
-
- return p > dst_len ? dst_len : p;
-#undef _PR
-}
-
-size_t snprint_edm_trace(struct PVRSRV_SGXDEV_INFO *sdev, char *buf,
- size_t buf_size)
-{
- return __print_edm_trace(sdev, buf, buf_size);
-}
-
-#endif
-
-static void dump_edm(struct PVRSRV_SGXDEV_INFO *sdev)
-{
-#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
- __print_edm_trace(sdev, NULL, 0);
-#endif
-}
-
static struct PVRSRV_PER_PROCESS_DATA *find_cur_proc_data(
struct PVRSRV_DEVICE_NODE *dev)
{
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;
+ struct task_struct *tsk;
+ int pid;
- 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();
- }
+ 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();
}
-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)
-{
- 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)
- 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;
-
- return buf;
-}
-
-static void dump_state_buf_list(struct PVRSRV_PER_PROCESS_DATA *proc,
- struct render_state_buf_list *bl)
-{
- int i;
-
- 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;
-
- 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;
-
- dump_state_buf_list(proc, mbl);
- kfree(mbl);
-}
-
/* 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);
- dump_process_info(psDeviceNode);
- dump_sgx_registers(psDevInfo);
- dump_edm(psDevInfo);
- dump_sgx_state_bufs(psDeviceNode);
+ proc = find_cur_proc_data(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_DEBUG_FS
+ 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);