aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/atom.c')
-rw-r--r--drivers/gpu/drm/radeon/atom.c105
1 files changed, 81 insertions, 24 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index d75788feac6c..1d569830ed99 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -24,6 +24,7 @@
24 24
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27#include <linux/slab.h>
27#include <asm/unaligned.h> 28#include <asm/unaligned.h>
28 29
29#define ATOM_DEBUG 30#define ATOM_DEBUG
@@ -52,15 +53,17 @@
52 53
53typedef struct { 54typedef struct {
54 struct atom_context *ctx; 55 struct atom_context *ctx;
55
56 uint32_t *ps, *ws; 56 uint32_t *ps, *ws;
57 int ps_shift; 57 int ps_shift;
58 uint16_t start; 58 uint16_t start;
59 unsigned last_jump;
60 unsigned long last_jump_jiffies;
61 bool abort;
59} atom_exec_context; 62} atom_exec_context;
60 63
61int atom_debug = 0; 64int atom_debug = 0;
62static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); 65static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
63void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); 66int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
64 67
65static uint32_t atom_arg_mask[8] = 68static uint32_t atom_arg_mask[8] =
66 { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 69 { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
@@ -604,12 +607,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
604static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 607static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
605{ 608{
606 int idx = U8((*ptr)++); 609 int idx = U8((*ptr)++);
610 int r = 0;
611
607 if (idx < ATOM_TABLE_NAMES_CNT) 612 if (idx < ATOM_TABLE_NAMES_CNT)
608 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); 613 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
609 else 614 else
610 SDEBUG(" table: %d\n", idx); 615 SDEBUG(" table: %d\n", idx);
611 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) 616 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
612 atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); 617 r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
618 if (r) {
619 ctx->abort = true;
620 }
613} 621}
614 622
615static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) 623static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
@@ -673,6 +681,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
673static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) 681static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
674{ 682{
675 int execute = 0, target = U16(*ptr); 683 int execute = 0, target = U16(*ptr);
684 unsigned long cjiffies;
685
676 (*ptr) += 2; 686 (*ptr) += 2;
677 switch (arg) { 687 switch (arg) {
678 case ATOM_COND_ABOVE: 688 case ATOM_COND_ABOVE:
@@ -700,8 +710,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
700 if (arg != ATOM_COND_ALWAYS) 710 if (arg != ATOM_COND_ALWAYS)
701 SDEBUG(" taken: %s\n", execute ? "yes" : "no"); 711 SDEBUG(" taken: %s\n", execute ? "yes" : "no");
702 SDEBUG(" target: 0x%04X\n", target); 712 SDEBUG(" target: 0x%04X\n", target);
703 if (execute) 713 if (execute) {
714 if (ctx->last_jump == (ctx->start + target)) {
715 cjiffies = jiffies;
716 if (time_after(cjiffies, ctx->last_jump_jiffies)) {
717 cjiffies -= ctx->last_jump_jiffies;
718 if ((jiffies_to_msecs(cjiffies) > 1000)) {
719 DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n");
720 ctx->abort = true;
721 }
722 } else {
723 /* jiffies wrap around we will just wait a little longer */
724 ctx->last_jump_jiffies = jiffies;
725 }
726 } else {
727 ctx->last_jump = ctx->start + target;
728 ctx->last_jump_jiffies = jiffies;
729 }
704 *ptr = ctx->start + target; 730 *ptr = ctx->start + target;
731 }
705} 732}
706 733
707static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) 734static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
@@ -881,11 +908,16 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
881 uint8_t attr = U8((*ptr)++), shift; 908 uint8_t attr = U8((*ptr)++), shift;
882 uint32_t saved, dst; 909 uint32_t saved, dst;
883 int dptr = *ptr; 910 int dptr = *ptr;
911 uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
884 SDEBUG(" dst: "); 912 SDEBUG(" dst: ");
885 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 913 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
914 /* op needs to full dst value */
915 dst = saved;
886 shift = atom_get_src(ctx, attr, ptr); 916 shift = atom_get_src(ctx, attr, ptr);
887 SDEBUG(" shift: %d\n", shift); 917 SDEBUG(" shift: %d\n", shift);
888 dst <<= shift; 918 dst <<= shift;
919 dst &= atom_arg_mask[dst_align];
920 dst >>= atom_arg_shift[dst_align];
889 SDEBUG(" dst: "); 921 SDEBUG(" dst: ");
890 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 922 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
891} 923}
@@ -895,11 +927,16 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
895 uint8_t attr = U8((*ptr)++), shift; 927 uint8_t attr = U8((*ptr)++), shift;
896 uint32_t saved, dst; 928 uint32_t saved, dst;
897 int dptr = *ptr; 929 int dptr = *ptr;
930 uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
898 SDEBUG(" dst: "); 931 SDEBUG(" dst: ");
899 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 932 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
933 /* op needs to full dst value */
934 dst = saved;
900 shift = atom_get_src(ctx, attr, ptr); 935 shift = atom_get_src(ctx, attr, ptr);
901 SDEBUG(" shift: %d\n", shift); 936 SDEBUG(" shift: %d\n", shift);
902 dst >>= shift; 937 dst >>= shift;
938 dst &= atom_arg_mask[dst_align];
939 dst >>= atom_arg_shift[dst_align];
903 SDEBUG(" dst: "); 940 SDEBUG(" dst: ");
904 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 941 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
905} 942}
@@ -1104,15 +1141,16 @@ static struct {
1104 atom_op_shr, ATOM_ARG_MC}, { 1141 atom_op_shr, ATOM_ARG_MC}, {
1105atom_op_debug, 0},}; 1142atom_op_debug, 0},};
1106 1143
1107static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) 1144static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1108{ 1145{
1109 int base = CU16(ctx->cmd_table + 4 + 2 * index); 1146 int base = CU16(ctx->cmd_table + 4 + 2 * index);
1110 int len, ws, ps, ptr; 1147 int len, ws, ps, ptr;
1111 unsigned char op; 1148 unsigned char op;
1112 atom_exec_context ectx; 1149 atom_exec_context ectx;
1150 int ret = 0;
1113 1151
1114 if (!base) 1152 if (!base)
1115 return; 1153 return -EINVAL;
1116 1154
1117 len = CU16(base + ATOM_CT_SIZE_PTR); 1155 len = CU16(base + ATOM_CT_SIZE_PTR);
1118 ws = CU8(base + ATOM_CT_WS_PTR); 1156 ws = CU8(base + ATOM_CT_WS_PTR);
@@ -1125,6 +1163,8 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
1125 ectx.ps_shift = ps / 4; 1163 ectx.ps_shift = ps / 4;
1126 ectx.start = base; 1164 ectx.start = base;
1127 ectx.ps = params; 1165 ectx.ps = params;
1166 ectx.abort = false;
1167 ectx.last_jump = 0;
1128 if (ws) 1168 if (ws)
1129 ectx.ws = kzalloc(4 * ws, GFP_KERNEL); 1169 ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1130 else 1170 else
@@ -1137,6 +1177,12 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
1137 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); 1177 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1138 else 1178 else
1139 SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); 1179 SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1180 if (ectx.abort) {
1181 DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1182 base, len, ws, ps, ptr - 1);
1183 ret = -EINVAL;
1184 goto free;
1185 }
1140 1186
1141 if (op < ATOM_OP_CNT && op > 0) 1187 if (op < ATOM_OP_CNT && op > 0)
1142 opcode_table[op].func(&ectx, &ptr, 1188 opcode_table[op].func(&ectx, &ptr,
@@ -1150,12 +1196,16 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
1150 debug_depth--; 1196 debug_depth--;
1151 SDEBUG("<<\n"); 1197 SDEBUG("<<\n");
1152 1198
1199free:
1153 if (ws) 1200 if (ws)
1154 kfree(ectx.ws); 1201 kfree(ectx.ws);
1202 return ret;
1155} 1203}
1156 1204
1157void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) 1205int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1158{ 1206{
1207 int r;
1208
1159 mutex_lock(&ctx->mutex); 1209 mutex_lock(&ctx->mutex);
1160 /* reset reg block */ 1210 /* reset reg block */
1161 ctx->reg_block = 0; 1211 ctx->reg_block = 0;
@@ -1163,8 +1213,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1163 ctx->fb_base = 0; 1213 ctx->fb_base = 0;
1164 /* reset io mode */ 1214 /* reset io mode */
1165 ctx->io_mode = ATOM_IO_MM; 1215 ctx->io_mode = ATOM_IO_MM;
1166 atom_execute_table_locked(ctx, index, params); 1216 r = atom_execute_table_locked(ctx, index, params);
1167 mutex_unlock(&ctx->mutex); 1217 mutex_unlock(&ctx->mutex);
1218 return r;
1168} 1219}
1169 1220
1170static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 1221static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
@@ -1248,9 +1299,7 @@ int atom_asic_init(struct atom_context *ctx)
1248 1299
1249 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) 1300 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1250 return 1; 1301 return 1;
1251 atom_execute_table(ctx, ATOM_CMD_INIT, ps); 1302 return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1252
1253 return 0;
1254} 1303}
1255 1304
1256void atom_destroy(struct atom_context *ctx) 1305void atom_destroy(struct atom_context *ctx)
@@ -1260,12 +1309,16 @@ void atom_destroy(struct atom_context *ctx)
1260 kfree(ctx); 1309 kfree(ctx);
1261} 1310}
1262 1311
1263void atom_parse_data_header(struct atom_context *ctx, int index, 1312bool atom_parse_data_header(struct atom_context *ctx, int index,
1264 uint16_t * size, uint8_t * frev, uint8_t * crev, 1313 uint16_t * size, uint8_t * frev, uint8_t * crev,
1265 uint16_t * data_start) 1314 uint16_t * data_start)
1266{ 1315{
1267 int offset = index * 2 + 4; 1316 int offset = index * 2 + 4;
1268 int idx = CU16(ctx->data_table + offset); 1317 int idx = CU16(ctx->data_table + offset);
1318 u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1319
1320 if (!mdt[index])
1321 return false;
1269 1322
1270 if (size) 1323 if (size)
1271 *size = CU16(idx); 1324 *size = CU16(idx);
@@ -1274,38 +1327,42 @@ void atom_parse_data_header(struct atom_context *ctx, int index,
1274 if (crev) 1327 if (crev)
1275 *crev = CU8(idx + 3); 1328 *crev = CU8(idx + 3);
1276 *data_start = idx; 1329 *data_start = idx;
1277 return; 1330 return true;
1278} 1331}
1279 1332
1280void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, 1333bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1281 uint8_t * crev) 1334 uint8_t * crev)
1282{ 1335{
1283 int offset = index * 2 + 4; 1336 int offset = index * 2 + 4;
1284 int idx = CU16(ctx->cmd_table + offset); 1337 int idx = CU16(ctx->cmd_table + offset);
1338 u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1339
1340 if (!mct[index])
1341 return false;
1285 1342
1286 if (frev) 1343 if (frev)
1287 *frev = CU8(idx + 2); 1344 *frev = CU8(idx + 2);
1288 if (crev) 1345 if (crev)
1289 *crev = CU8(idx + 3); 1346 *crev = CU8(idx + 3);
1290 return; 1347 return true;
1291} 1348}
1292 1349
1293int atom_allocate_fb_scratch(struct atom_context *ctx) 1350int atom_allocate_fb_scratch(struct atom_context *ctx)
1294{ 1351{
1295 int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); 1352 int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1296 uint16_t data_offset; 1353 uint16_t data_offset;
1297 int usage_bytes; 1354 int usage_bytes = 0;
1298 struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; 1355 struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1299 1356
1300 atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); 1357 if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
1358 firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1301 1359
1302 firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); 1360 DRM_DEBUG("atom firmware requested %08x %dkb\n",
1361 firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
1362 firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1303 1363
1304 DRM_DEBUG("atom firmware requested %08x %dkb\n", 1364 usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1305 firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, 1365 }
1306 firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1307
1308 usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1309 if (usage_bytes == 0) 1366 if (usage_bytes == 0)
1310 usage_bytes = 20 * 1024; 1367 usage_bytes = 20 * 1024;
1311 /* allocate some scratch memory */ 1368 /* allocate some scratch memory */