diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/gpu/drm/radeon/atom.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/gpu/drm/radeon/atom.c')
-rw-r--r-- | drivers/gpu/drm/radeon/atom.c | 233 |
1 files changed, 195 insertions, 38 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d67c42555ab9..1d569830ed99 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c | |||
@@ -24,6 +24,8 @@ | |||
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> | ||
28 | #include <asm/unaligned.h> | ||
27 | 29 | ||
28 | #define ATOM_DEBUG | 30 | #define ATOM_DEBUG |
29 | 31 | ||
@@ -51,14 +53,17 @@ | |||
51 | 53 | ||
52 | typedef struct { | 54 | typedef struct { |
53 | struct atom_context *ctx; | 55 | struct atom_context *ctx; |
54 | |||
55 | uint32_t *ps, *ws; | 56 | uint32_t *ps, *ws; |
56 | int ps_shift; | 57 | int ps_shift; |
57 | uint16_t start; | 58 | uint16_t start; |
59 | unsigned last_jump; | ||
60 | unsigned long last_jump_jiffies; | ||
61 | bool abort; | ||
58 | } atom_exec_context; | 62 | } atom_exec_context; |
59 | 63 | ||
60 | int atom_debug = 0; | 64 | int atom_debug = 0; |
61 | void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); | 65 | static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); |
66 | int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); | ||
62 | 67 | ||
63 | static uint32_t atom_arg_mask[8] = | 68 | static uint32_t atom_arg_mask[8] = |
64 | { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, | 69 | { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, |
@@ -211,7 +216,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, | |||
211 | case ATOM_ARG_PS: | 216 | case ATOM_ARG_PS: |
212 | idx = U8(*ptr); | 217 | idx = U8(*ptr); |
213 | (*ptr)++; | 218 | (*ptr)++; |
214 | val = le32_to_cpu(ctx->ps[idx]); | 219 | /* get_unaligned_le32 avoids unaligned accesses from atombios |
220 | * tables, noticed on a DEC Alpha. */ | ||
221 | val = get_unaligned_le32((u32 *)&ctx->ps[idx]); | ||
215 | if (print) | 222 | if (print) |
216 | DEBUG("PS[0x%02X,0x%04X]", idx, val); | 223 | DEBUG("PS[0x%02X,0x%04X]", idx, val); |
217 | break; | 224 | break; |
@@ -245,6 +252,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, | |||
245 | case ATOM_WS_ATTRIBUTES: | 252 | case ATOM_WS_ATTRIBUTES: |
246 | val = gctx->io_attr; | 253 | val = gctx->io_attr; |
247 | break; | 254 | break; |
255 | case ATOM_WS_REGPTR: | ||
256 | val = gctx->reg_block; | ||
257 | break; | ||
248 | default: | 258 | default: |
249 | val = ctx->ws[idx]; | 259 | val = ctx->ws[idx]; |
250 | } | 260 | } |
@@ -263,10 +273,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, | |||
263 | case ATOM_ARG_FB: | 273 | case ATOM_ARG_FB: |
264 | idx = U8(*ptr); | 274 | idx = U8(*ptr); |
265 | (*ptr)++; | 275 | (*ptr)++; |
276 | val = gctx->scratch[((gctx->fb_base + idx) / 4)]; | ||
266 | if (print) | 277 | if (print) |
267 | DEBUG("FB[0x%02X]", idx); | 278 | DEBUG("FB[0x%02X]", idx); |
268 | printk(KERN_INFO "FB access is not implemented.\n"); | 279 | break; |
269 | return 0; | ||
270 | case ATOM_ARG_IMM: | 280 | case ATOM_ARG_IMM: |
271 | switch (align) { | 281 | switch (align) { |
272 | case ATOM_SRC_DWORD: | 282 | case ATOM_SRC_DWORD: |
@@ -384,6 +394,32 @@ static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) | |||
384 | return atom_get_src_int(ctx, attr, ptr, NULL, 1); | 394 | return atom_get_src_int(ctx, attr, ptr, NULL, 1); |
385 | } | 395 | } |
386 | 396 | ||
397 | static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) | ||
398 | { | ||
399 | uint32_t val = 0xCDCDCDCD; | ||
400 | |||
401 | switch (align) { | ||
402 | case ATOM_SRC_DWORD: | ||
403 | val = U32(*ptr); | ||
404 | (*ptr) += 4; | ||
405 | break; | ||
406 | case ATOM_SRC_WORD0: | ||
407 | case ATOM_SRC_WORD8: | ||
408 | case ATOM_SRC_WORD16: | ||
409 | val = U16(*ptr); | ||
410 | (*ptr) += 2; | ||
411 | break; | ||
412 | case ATOM_SRC_BYTE0: | ||
413 | case ATOM_SRC_BYTE8: | ||
414 | case ATOM_SRC_BYTE16: | ||
415 | case ATOM_SRC_BYTE24: | ||
416 | val = U8(*ptr); | ||
417 | (*ptr)++; | ||
418 | break; | ||
419 | } | ||
420 | return val; | ||
421 | } | ||
422 | |||
387 | static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, | 423 | static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, |
388 | int *ptr, uint32_t *saved, int print) | 424 | int *ptr, uint32_t *saved, int print) |
389 | { | 425 | { |
@@ -481,6 +517,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, | |||
481 | case ATOM_WS_ATTRIBUTES: | 517 | case ATOM_WS_ATTRIBUTES: |
482 | gctx->io_attr = val; | 518 | gctx->io_attr = val; |
483 | break; | 519 | break; |
520 | case ATOM_WS_REGPTR: | ||
521 | gctx->reg_block = val; | ||
522 | break; | ||
484 | default: | 523 | default: |
485 | ctx->ws[idx] = val; | 524 | ctx->ws[idx] = val; |
486 | } | 525 | } |
@@ -488,9 +527,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, | |||
488 | case ATOM_ARG_FB: | 527 | case ATOM_ARG_FB: |
489 | idx = U8(*ptr); | 528 | idx = U8(*ptr); |
490 | (*ptr)++; | 529 | (*ptr)++; |
530 | gctx->scratch[((gctx->fb_base + idx) / 4)] = val; | ||
491 | DEBUG("FB[0x%02X]", idx); | 531 | DEBUG("FB[0x%02X]", idx); |
492 | printk(KERN_INFO "FB access is not implemented.\n"); | 532 | break; |
493 | return; | ||
494 | case ATOM_ARG_PLL: | 533 | case ATOM_ARG_PLL: |
495 | idx = U8(*ptr); | 534 | idx = U8(*ptr); |
496 | (*ptr)++; | 535 | (*ptr)++; |
@@ -568,12 +607,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) | |||
568 | static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) | 607 | static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) |
569 | { | 608 | { |
570 | int idx = U8((*ptr)++); | 609 | int idx = U8((*ptr)++); |
610 | int r = 0; | ||
611 | |||
571 | if (idx < ATOM_TABLE_NAMES_CNT) | 612 | if (idx < ATOM_TABLE_NAMES_CNT) |
572 | SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); | 613 | SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); |
573 | else | 614 | else |
574 | SDEBUG(" table: %d\n", idx); | 615 | SDEBUG(" table: %d\n", idx); |
575 | if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) | 616 | if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) |
576 | atom_execute_table(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 | } | ||
577 | } | 621 | } |
578 | 622 | ||
579 | static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) | 623 | static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) |
@@ -607,7 +651,7 @@ static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) | |||
607 | uint8_t count = U8((*ptr)++); | 651 | uint8_t count = U8((*ptr)++); |
608 | SDEBUG(" count: %d\n", count); | 652 | SDEBUG(" count: %d\n", count); |
609 | if (arg == ATOM_UNIT_MICROSEC) | 653 | if (arg == ATOM_UNIT_MICROSEC) |
610 | schedule_timeout_uninterruptible(usecs_to_jiffies(count)); | 654 | udelay(count); |
611 | else | 655 | else |
612 | schedule_timeout_uninterruptible(msecs_to_jiffies(count)); | 656 | schedule_timeout_uninterruptible(msecs_to_jiffies(count)); |
613 | } | 657 | } |
@@ -637,6 +681,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) | |||
637 | static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) | 681 | static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) |
638 | { | 682 | { |
639 | int execute = 0, target = U16(*ptr); | 683 | int execute = 0, target = U16(*ptr); |
684 | unsigned long cjiffies; | ||
685 | |||
640 | (*ptr) += 2; | 686 | (*ptr) += 2; |
641 | switch (arg) { | 687 | switch (arg) { |
642 | case ATOM_COND_ABOVE: | 688 | case ATOM_COND_ABOVE: |
@@ -664,8 +710,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) | |||
664 | if (arg != ATOM_COND_ALWAYS) | 710 | if (arg != ATOM_COND_ALWAYS) |
665 | SDEBUG(" taken: %s\n", execute ? "yes" : "no"); | 711 | SDEBUG(" taken: %s\n", execute ? "yes" : "no"); |
666 | SDEBUG(" target: 0x%04X\n", target); | 712 | SDEBUG(" target: 0x%04X\n", target); |
667 | 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 | } | ||
668 | *ptr = ctx->start + target; | 730 | *ptr = ctx->start + target; |
731 | } | ||
669 | } | 732 | } |
670 | 733 | ||
671 | static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) | 734 | static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) |
@@ -676,7 +739,7 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) | |||
676 | SDEBUG(" dst: "); | 739 | SDEBUG(" dst: "); |
677 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); | 740 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
678 | SDEBUG(" src1: "); | 741 | SDEBUG(" src1: "); |
679 | src1 = atom_get_src(ctx, attr, ptr); | 742 | src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); |
680 | SDEBUG(" src2: "); | 743 | SDEBUG(" src2: "); |
681 | src2 = atom_get_src(ctx, attr, ptr); | 744 | src2 = atom_get_src(ctx, attr, ptr); |
682 | dst &= src1; | 745 | dst &= src1; |
@@ -808,7 +871,7 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) | |||
808 | SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); | 871 | SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); |
809 | } | 872 | } |
810 | 873 | ||
811 | static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) | 874 | static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) |
812 | { | 875 | { |
813 | uint8_t attr = U8((*ptr)++), shift; | 876 | uint8_t attr = U8((*ptr)++), shift; |
814 | uint32_t saved, dst; | 877 | uint32_t saved, dst; |
@@ -817,14 +880,14 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) | |||
817 | attr |= atom_def_dst[attr >> 3] << 6; | 880 | attr |= atom_def_dst[attr >> 3] << 6; |
818 | SDEBUG(" dst: "); | 881 | SDEBUG(" dst: "); |
819 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); | 882 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
820 | shift = U8((*ptr)++); | 883 | shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); |
821 | SDEBUG(" shift: %d\n", shift); | 884 | SDEBUG(" shift: %d\n", shift); |
822 | dst <<= shift; | 885 | dst <<= shift; |
823 | SDEBUG(" dst: "); | 886 | SDEBUG(" dst: "); |
824 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); | 887 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); |
825 | } | 888 | } |
826 | 889 | ||
827 | static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) | 890 | static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) |
828 | { | 891 | { |
829 | uint8_t attr = U8((*ptr)++), shift; | 892 | uint8_t attr = U8((*ptr)++), shift; |
830 | uint32_t saved, dst; | 893 | uint32_t saved, dst; |
@@ -833,9 +896,47 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) | |||
833 | attr |= atom_def_dst[attr >> 3] << 6; | 896 | attr |= atom_def_dst[attr >> 3] << 6; |
834 | SDEBUG(" dst: "); | 897 | SDEBUG(" dst: "); |
835 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); | 898 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
836 | shift = U8((*ptr)++); | 899 | shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); |
900 | SDEBUG(" shift: %d\n", shift); | ||
901 | dst >>= shift; | ||
902 | SDEBUG(" dst: "); | ||
903 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); | ||
904 | } | ||
905 | |||
906 | static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) | ||
907 | { | ||
908 | uint8_t attr = U8((*ptr)++), shift; | ||
909 | uint32_t saved, dst; | ||
910 | int dptr = *ptr; | ||
911 | uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; | ||
912 | SDEBUG(" dst: "); | ||
913 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); | ||
914 | /* op needs to full dst value */ | ||
915 | dst = saved; | ||
916 | shift = atom_get_src(ctx, attr, ptr); | ||
917 | SDEBUG(" shift: %d\n", shift); | ||
918 | dst <<= shift; | ||
919 | dst &= atom_arg_mask[dst_align]; | ||
920 | dst >>= atom_arg_shift[dst_align]; | ||
921 | SDEBUG(" dst: "); | ||
922 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); | ||
923 | } | ||
924 | |||
925 | static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) | ||
926 | { | ||
927 | uint8_t attr = U8((*ptr)++), shift; | ||
928 | uint32_t saved, dst; | ||
929 | int dptr = *ptr; | ||
930 | uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; | ||
931 | SDEBUG(" dst: "); | ||
932 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); | ||
933 | /* op needs to full dst value */ | ||
934 | dst = saved; | ||
935 | shift = atom_get_src(ctx, attr, ptr); | ||
837 | SDEBUG(" shift: %d\n", shift); | 936 | SDEBUG(" shift: %d\n", shift); |
838 | dst >>= shift; | 937 | dst >>= shift; |
938 | dst &= atom_arg_mask[dst_align]; | ||
939 | dst >>= atom_arg_shift[dst_align]; | ||
839 | SDEBUG(" dst: "); | 940 | SDEBUG(" dst: "); |
840 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); | 941 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); |
841 | } | 942 | } |
@@ -936,18 +1037,18 @@ static struct { | |||
936 | atom_op_or, ATOM_ARG_FB}, { | 1037 | atom_op_or, ATOM_ARG_FB}, { |
937 | atom_op_or, ATOM_ARG_PLL}, { | 1038 | atom_op_or, ATOM_ARG_PLL}, { |
938 | atom_op_or, ATOM_ARG_MC}, { | 1039 | atom_op_or, ATOM_ARG_MC}, { |
939 | atom_op_shl, ATOM_ARG_REG}, { | 1040 | atom_op_shift_left, ATOM_ARG_REG}, { |
940 | atom_op_shl, ATOM_ARG_PS}, { | 1041 | atom_op_shift_left, ATOM_ARG_PS}, { |
941 | atom_op_shl, ATOM_ARG_WS}, { | 1042 | atom_op_shift_left, ATOM_ARG_WS}, { |
942 | atom_op_shl, ATOM_ARG_FB}, { | 1043 | atom_op_shift_left, ATOM_ARG_FB}, { |
943 | atom_op_shl, ATOM_ARG_PLL}, { | 1044 | atom_op_shift_left, ATOM_ARG_PLL}, { |
944 | atom_op_shl, ATOM_ARG_MC}, { | 1045 | atom_op_shift_left, ATOM_ARG_MC}, { |
945 | atom_op_shr, ATOM_ARG_REG}, { | 1046 | atom_op_shift_right, ATOM_ARG_REG}, { |
946 | atom_op_shr, ATOM_ARG_PS}, { | 1047 | atom_op_shift_right, ATOM_ARG_PS}, { |
947 | atom_op_shr, ATOM_ARG_WS}, { | 1048 | atom_op_shift_right, ATOM_ARG_WS}, { |
948 | atom_op_shr, ATOM_ARG_FB}, { | 1049 | atom_op_shift_right, ATOM_ARG_FB}, { |
949 | atom_op_shr, ATOM_ARG_PLL}, { | 1050 | atom_op_shift_right, ATOM_ARG_PLL}, { |
950 | atom_op_shr, ATOM_ARG_MC}, { | 1051 | atom_op_shift_right, ATOM_ARG_MC}, { |
951 | atom_op_mul, ATOM_ARG_REG}, { | 1052 | atom_op_mul, ATOM_ARG_REG}, { |
952 | atom_op_mul, ATOM_ARG_PS}, { | 1053 | atom_op_mul, ATOM_ARG_PS}, { |
953 | atom_op_mul, ATOM_ARG_WS}, { | 1054 | atom_op_mul, ATOM_ARG_WS}, { |
@@ -1040,15 +1141,16 @@ static struct { | |||
1040 | atom_op_shr, ATOM_ARG_MC}, { | 1141 | atom_op_shr, ATOM_ARG_MC}, { |
1041 | atom_op_debug, 0},}; | 1142 | atom_op_debug, 0},}; |
1042 | 1143 | ||
1043 | void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) | 1144 | static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) |
1044 | { | 1145 | { |
1045 | int base = CU16(ctx->cmd_table + 4 + 2 * index); | 1146 | int base = CU16(ctx->cmd_table + 4 + 2 * index); |
1046 | int len, ws, ps, ptr; | 1147 | int len, ws, ps, ptr; |
1047 | unsigned char op; | 1148 | unsigned char op; |
1048 | atom_exec_context ectx; | 1149 | atom_exec_context ectx; |
1150 | int ret = 0; | ||
1049 | 1151 | ||
1050 | if (!base) | 1152 | if (!base) |
1051 | return; | 1153 | return -EINVAL; |
1052 | 1154 | ||
1053 | len = CU16(base + ATOM_CT_SIZE_PTR); | 1155 | len = CU16(base + ATOM_CT_SIZE_PTR); |
1054 | ws = CU8(base + ATOM_CT_WS_PTR); | 1156 | ws = CU8(base + ATOM_CT_WS_PTR); |
@@ -1057,12 +1159,12 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) | |||
1057 | 1159 | ||
1058 | SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); | 1160 | SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); |
1059 | 1161 | ||
1060 | /* reset reg block */ | ||
1061 | ctx->reg_block = 0; | ||
1062 | ectx.ctx = ctx; | 1162 | ectx.ctx = ctx; |
1063 | ectx.ps_shift = ps / 4; | 1163 | ectx.ps_shift = ps / 4; |
1064 | ectx.start = base; | 1164 | ectx.start = base; |
1065 | ectx.ps = params; | 1165 | ectx.ps = params; |
1166 | ectx.abort = false; | ||
1167 | ectx.last_jump = 0; | ||
1066 | if (ws) | 1168 | if (ws) |
1067 | ectx.ws = kzalloc(4 * ws, GFP_KERNEL); | 1169 | ectx.ws = kzalloc(4 * ws, GFP_KERNEL); |
1068 | else | 1170 | else |
@@ -1075,6 +1177,12 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) | |||
1075 | SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); | 1177 | SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); |
1076 | else | 1178 | else |
1077 | 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 | } | ||
1078 | 1186 | ||
1079 | if (op < ATOM_OP_CNT && op > 0) | 1187 | if (op < ATOM_OP_CNT && op > 0) |
1080 | opcode_table[op].func(&ectx, &ptr, | 1188 | opcode_table[op].func(&ectx, &ptr, |
@@ -1088,8 +1196,26 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) | |||
1088 | debug_depth--; | 1196 | debug_depth--; |
1089 | SDEBUG("<<\n"); | 1197 | SDEBUG("<<\n"); |
1090 | 1198 | ||
1199 | free: | ||
1091 | if (ws) | 1200 | if (ws) |
1092 | kfree(ectx.ws); | 1201 | kfree(ectx.ws); |
1202 | return ret; | ||
1203 | } | ||
1204 | |||
1205 | int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) | ||
1206 | { | ||
1207 | int r; | ||
1208 | |||
1209 | mutex_lock(&ctx->mutex); | ||
1210 | /* reset reg block */ | ||
1211 | ctx->reg_block = 0; | ||
1212 | /* reset fb window */ | ||
1213 | ctx->fb_base = 0; | ||
1214 | /* reset io mode */ | ||
1215 | ctx->io_mode = ATOM_IO_MM; | ||
1216 | r = atom_execute_table_locked(ctx, index, params); | ||
1217 | mutex_unlock(&ctx->mutex); | ||
1218 | return r; | ||
1093 | } | 1219 | } |
1094 | 1220 | ||
1095 | static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; | 1221 | static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; |
@@ -1173,9 +1299,7 @@ int atom_asic_init(struct atom_context *ctx) | |||
1173 | 1299 | ||
1174 | if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) | 1300 | if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) |
1175 | return 1; | 1301 | return 1; |
1176 | atom_execute_table(ctx, ATOM_CMD_INIT, ps); | 1302 | return atom_execute_table(ctx, ATOM_CMD_INIT, ps); |
1177 | |||
1178 | return 0; | ||
1179 | } | 1303 | } |
1180 | 1304 | ||
1181 | void atom_destroy(struct atom_context *ctx) | 1305 | void atom_destroy(struct atom_context *ctx) |
@@ -1185,12 +1309,16 @@ void atom_destroy(struct atom_context *ctx) | |||
1185 | kfree(ctx); | 1309 | kfree(ctx); |
1186 | } | 1310 | } |
1187 | 1311 | ||
1188 | void atom_parse_data_header(struct atom_context *ctx, int index, | 1312 | bool atom_parse_data_header(struct atom_context *ctx, int index, |
1189 | uint16_t * size, uint8_t * frev, uint8_t * crev, | 1313 | uint16_t * size, uint8_t * frev, uint8_t * crev, |
1190 | uint16_t * data_start) | 1314 | uint16_t * data_start) |
1191 | { | 1315 | { |
1192 | int offset = index * 2 + 4; | 1316 | int offset = index * 2 + 4; |
1193 | 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; | ||
1194 | 1322 | ||
1195 | if (size) | 1323 | if (size) |
1196 | *size = CU16(idx); | 1324 | *size = CU16(idx); |
@@ -1199,18 +1327,47 @@ void atom_parse_data_header(struct atom_context *ctx, int index, | |||
1199 | if (crev) | 1327 | if (crev) |
1200 | *crev = CU8(idx + 3); | 1328 | *crev = CU8(idx + 3); |
1201 | *data_start = idx; | 1329 | *data_start = idx; |
1202 | return; | 1330 | return true; |
1203 | } | 1331 | } |
1204 | 1332 | ||
1205 | void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, | 1333 | bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, |
1206 | uint8_t * crev) | 1334 | uint8_t * crev) |
1207 | { | 1335 | { |
1208 | int offset = index * 2 + 4; | 1336 | int offset = index * 2 + 4; |
1209 | 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; | ||
1210 | 1342 | ||
1211 | if (frev) | 1343 | if (frev) |
1212 | *frev = CU8(idx + 2); | 1344 | *frev = CU8(idx + 2); |
1213 | if (crev) | 1345 | if (crev) |
1214 | *crev = CU8(idx + 3); | 1346 | *crev = CU8(idx + 3); |
1215 | return; | 1347 | return true; |
1348 | } | ||
1349 | |||
1350 | int atom_allocate_fb_scratch(struct atom_context *ctx) | ||
1351 | { | ||
1352 | int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); | ||
1353 | uint16_t data_offset; | ||
1354 | int usage_bytes = 0; | ||
1355 | struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; | ||
1356 | |||
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); | ||
1359 | |||
1360 | DRM_DEBUG("atom firmware requested %08x %dkb\n", | ||
1361 | firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, | ||
1362 | firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); | ||
1363 | |||
1364 | usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; | ||
1365 | } | ||
1366 | if (usage_bytes == 0) | ||
1367 | usage_bytes = 20 * 1024; | ||
1368 | /* allocate some scratch memory */ | ||
1369 | ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL); | ||
1370 | if (!ctx->scratch) | ||
1371 | return -ENOMEM; | ||
1372 | return 0; | ||
1216 | } | 1373 | } |