|
@@ -52,15 +52,17 @@
|
|
|
|
|
|
typedef struct {
|
|
|
struct atom_context *ctx;
|
|
|
-
|
|
|
uint32_t *ps, *ws;
|
|
|
int ps_shift;
|
|
|
uint16_t start;
|
|
|
+ unsigned last_jump;
|
|
|
+ unsigned long last_jump_jiffies;
|
|
|
+ bool abort;
|
|
|
} atom_exec_context;
|
|
|
|
|
|
int atom_debug = 0;
|
|
|
-static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
|
|
|
-void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
|
|
|
+static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
|
|
|
+int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
|
|
|
|
|
|
static uint32_t atom_arg_mask[8] =
|
|
|
{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
|
|
@@ -604,12 +606,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
|
|
|
static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
|
|
|
{
|
|
|
int idx = U8((*ptr)++);
|
|
|
+ int r = 0;
|
|
|
+
|
|
|
if (idx < ATOM_TABLE_NAMES_CNT)
|
|
|
SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
|
|
|
else
|
|
|
SDEBUG(" table: %d\n", idx);
|
|
|
if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
|
|
|
- atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
|
|
|
+ r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
|
|
|
+ if (r) {
|
|
|
+ ctx->abort = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
|
|
@@ -673,6 +680,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
|
|
|
static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
|
|
|
{
|
|
|
int execute = 0, target = U16(*ptr);
|
|
|
+ unsigned long cjiffies;
|
|
|
+
|
|
|
(*ptr) += 2;
|
|
|
switch (arg) {
|
|
|
case ATOM_COND_ABOVE:
|
|
@@ -700,8 +709,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
|
|
|
if (arg != ATOM_COND_ALWAYS)
|
|
|
SDEBUG(" taken: %s\n", execute ? "yes" : "no");
|
|
|
SDEBUG(" target: 0x%04X\n", target);
|
|
|
- if (execute)
|
|
|
+ if (execute) {
|
|
|
+ if (ctx->last_jump == (ctx->start + target)) {
|
|
|
+ cjiffies = jiffies;
|
|
|
+ if (time_after(cjiffies, ctx->last_jump_jiffies)) {
|
|
|
+ cjiffies -= ctx->last_jump_jiffies;
|
|
|
+ if ((jiffies_to_msecs(cjiffies) > 1000)) {
|
|
|
+ DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n");
|
|
|
+ ctx->abort = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* jiffies wrap around we will just wait a little longer */
|
|
|
+ ctx->last_jump_jiffies = jiffies;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ctx->last_jump = ctx->start + target;
|
|
|
+ ctx->last_jump_jiffies = jiffies;
|
|
|
+ }
|
|
|
*ptr = ctx->start + target;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
|
|
@@ -1104,7 +1130,7 @@ static struct {
|
|
|
atom_op_shr, ATOM_ARG_MC}, {
|
|
|
atom_op_debug, 0},};
|
|
|
|
|
|
-static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
|
|
|
+static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
|
|
|
{
|
|
|
int base = CU16(ctx->cmd_table + 4 + 2 * index);
|
|
|
int len, ws, ps, ptr;
|
|
@@ -1112,7 +1138,7 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|
|
atom_exec_context ectx;
|
|
|
|
|
|
if (!base)
|
|
|
- return;
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
len = CU16(base + ATOM_CT_SIZE_PTR);
|
|
|
ws = CU8(base + ATOM_CT_WS_PTR);
|
|
@@ -1125,6 +1151,8 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|
|
ectx.ps_shift = ps / 4;
|
|
|
ectx.start = base;
|
|
|
ectx.ps = params;
|
|
|
+ ectx.abort = false;
|
|
|
+ ectx.last_jump = 0;
|
|
|
if (ws)
|
|
|
ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
|
|
|
else
|
|
@@ -1137,6 +1165,11 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|
|
SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
|
|
|
else
|
|
|
SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
|
|
|
+ if (ectx.abort) {
|
|
|
+ DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
|
|
|
+ base, len, ws, ps, ptr - 1);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
if (op < ATOM_OP_CNT && op > 0)
|
|
|
opcode_table[op].func(&ectx, &ptr,
|
|
@@ -1152,10 +1185,13 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|
|
|
|
|
if (ws)
|
|
|
kfree(ectx.ws);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
|
|
+int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
|
|
{
|
|
|
+ int r;
|
|
|
+
|
|
|
mutex_lock(&ctx->mutex);
|
|
|
/* reset reg block */
|
|
|
ctx->reg_block = 0;
|
|
@@ -1163,8 +1199,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
|
|
ctx->fb_base = 0;
|
|
|
/* reset io mode */
|
|
|
ctx->io_mode = ATOM_IO_MM;
|
|
|
- atom_execute_table_locked(ctx, index, params);
|
|
|
+ r = atom_execute_table_locked(ctx, index, params);
|
|
|
mutex_unlock(&ctx->mutex);
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
|
|
@@ -1248,9 +1285,7 @@ int atom_asic_init(struct atom_context *ctx)
|
|
|
|
|
|
if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
|
|
|
return 1;
|
|
|
- atom_execute_table(ctx, ATOM_CMD_INIT, ps);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
|
|
|
}
|
|
|
|
|
|
void atom_destroy(struct atom_context *ctx)
|