summaryrefslogtreecommitdiff
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.c142
1 files changed, 85 insertions, 57 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index fb441a790f3d..b31125eb9a65 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -25,7 +25,12 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/string_helpers.h>
+
+#include <linux/unaligned.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_util.h>
#define ATOM_DEBUG
@@ -55,6 +60,7 @@
typedef struct {
struct atom_context *ctx;
uint32_t *ps, *ws;
+ int ps_size, ws_size;
int ps_shift;
uint16_t start;
unsigned last_jump;
@@ -63,12 +69,13 @@ typedef struct {
} atom_exec_context;
int atom_debug = 0;
-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 int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size);
+int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size);
-static uint32_t atom_arg_mask[8] =
- { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
-0xFF000000 };
+static uint32_t atom_arg_mask[8] = {
+ 0xFFFFFFFF, 0x0000FFFF, 0x00FFFF00, 0xFFFF0000,
+ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
+};
static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
static int atom_dst_to_src[8][4] = {
@@ -157,19 +164,15 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
CU8(base + 3));
temp |=
- ((ctx->
- io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
- CU8
- (base
- +
- 1))))
- << CU8(base + 3);
+ ((ctx->io_attr >> CU8(base + 2)) &
+ (0xFFFFFFFF >> (32 - CU8(base + 1)))) <<
+ CU8(base + 3);
base += 4;
break;
case ATOM_IIO_END:
return temp;
default:
- printk(KERN_INFO "Unknown IIO opcode.\n");
+ pr_info("Unknown IIO opcode\n");
return 0;
}
}
@@ -193,22 +196,19 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
val = gctx->card->reg_read(gctx->card, idx);
break;
case ATOM_IO_PCI:
- printk(KERN_INFO
- "PCI registers are not implemented.\n");
+ pr_info("PCI registers are not implemented\n");
return 0;
case ATOM_IO_SYSIO:
- printk(KERN_INFO
- "SYSIO registers are not implemented.\n");
+ pr_info("SYSIO registers are not implemented\n");
return 0;
default:
if (!(gctx->io_mode & 0x80)) {
- printk(KERN_INFO "Bad IO mode.\n");
+ pr_info("Bad IO mode\n");
return 0;
}
if (!gctx->iio[gctx->io_mode & 0x7F]) {
- printk(KERN_INFO
- "Undefined indirect IO read method %d.\n",
- gctx->io_mode & 0x7F);
+ pr_info("Undefined indirect IO read method %d\n",
+ gctx->io_mode & 0x7F);
return 0;
}
val =
@@ -222,7 +222,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
(*ptr)++;
/* get_unaligned_le32 avoids unaligned accesses from atombios
* tables, noticed on a DEC Alpha. */
- val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
+ if (idx < ctx->ps_size)
+ val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
+ else
+ pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
if (print)
DEBUG("PS[0x%02X,0x%04X]", idx, val);
break;
@@ -260,7 +263,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
val = gctx->reg_block;
break;
default:
- val = ctx->ws[idx];
+ if (idx < ctx->ws_size)
+ val = ctx->ws[idx];
+ else
+ pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
}
break;
case ATOM_ARG_ID:
@@ -472,22 +478,19 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
gctx->card->reg_write(gctx->card, idx, val);
break;
case ATOM_IO_PCI:
- printk(KERN_INFO
- "PCI registers are not implemented.\n");
+ pr_info("PCI registers are not implemented\n");
return;
case ATOM_IO_SYSIO:
- printk(KERN_INFO
- "SYSIO registers are not implemented.\n");
+ pr_info("SYSIO registers are not implemented\n");
return;
default:
if (!(gctx->io_mode & 0x80)) {
- printk(KERN_INFO "Bad IO mode.\n");
+ pr_info("Bad IO mode\n");
return;
}
if (!gctx->iio[gctx->io_mode & 0xFF]) {
- printk(KERN_INFO
- "Undefined indirect IO write method %d.\n",
- gctx->io_mode & 0x7F);
+ pr_info("Undefined indirect IO write method %d\n",
+ gctx->io_mode & 0x7F);
return;
}
atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
@@ -498,6 +501,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
idx = U8(*ptr);
(*ptr)++;
DEBUG("PS[0x%02X]", idx);
+ if (idx >= ctx->ps_size) {
+ pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
+ return;
+ }
ctx->ps[idx] = cpu_to_le32(val);
break;
case ATOM_ARG_WS:
@@ -530,6 +537,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
gctx->reg_block = val;
break;
default:
+ if (idx >= ctx->ws_size) {
+ pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
+ return;
+ }
ctx->ws[idx] = val;
}
break;
@@ -627,7 +638,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
else
SDEBUG(" table: %d\n", idx);
if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
- r = 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, ctx->ps_size - ctx->ps_shift);
if (r) {
ctx->abort = true;
}
@@ -723,7 +734,7 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
break;
}
if (arg != ATOM_COND_ALWAYS)
- SDEBUG(" taken: %s\n", execute ? "yes" : "no");
+ SDEBUG(" taken: %s\n", str_yes_no(execute));
SDEBUG(" target: 0x%04X\n", target);
if (execute) {
if (ctx->last_jump == (ctx->start + target)) {
@@ -818,17 +829,17 @@ static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
{
- printk(KERN_INFO "unimplemented!\n");
+ pr_info("unimplemented!\n");
}
static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
{
- printk(KERN_INFO "unimplemented!\n");
+ pr_info("unimplemented!\n");
}
static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
{
- printk(KERN_INFO "unimplemented!\n");
+ pr_info("unimplemented!\n");
}
static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
@@ -991,7 +1002,7 @@ static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
}
(*ptr) += 2;
} else {
- printk(KERN_INFO "Bad case.\n");
+ pr_info("Bad case\n");
return;
}
(*ptr) += 2;
@@ -1025,7 +1036,7 @@ static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
{
- printk(KERN_INFO "unimplemented!\n");
+ pr_info("unimplemented!\n");
}
static struct {
@@ -1156,7 +1167,7 @@ static struct {
atom_op_shr, ATOM_ARG_MC}, {
atom_op_debug, 0},};
-static int 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 params_size)
{
int base = CU16(ctx->cmd_table + 4 + 2 * index);
int len, ws, ps, ptr;
@@ -1178,12 +1189,16 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
ectx.ps_shift = ps / 4;
ectx.start = base;
ectx.ps = params;
+ ectx.ps_size = params_size;
ectx.abort = false;
ectx.last_jump = 0;
- if (ws)
- ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
- else
+ if (ws) {
+ ectx.ws = kcalloc(4, ws, GFP_KERNEL);
+ ectx.ws_size = ws;
+ } else {
ectx.ws = NULL;
+ ectx.ws_size = 0;
+ }
debug_depth++;
while (1) {
@@ -1212,27 +1227,40 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
SDEBUG("<<\n");
free:
- if (ws)
- kfree(ectx.ws);
+ kfree(ectx.ws);
return ret;
}
-int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t *params, int params_size)
{
int r;
mutex_lock(&ctx->mutex);
+ /* reset data block */
+ ctx->data_block = 0;
/* reset reg block */
ctx->reg_block = 0;
/* reset fb window */
ctx->fb_base = 0;
/* reset io mode */
ctx->io_mode = ATOM_IO_MM;
- r = atom_execute_table_locked(ctx, index, params);
+ /* reset divmul */
+ ctx->divmul[0] = 0;
+ ctx->divmul[1] = 0;
+ r = atom_execute_table_locked(ctx, index, params, params_size);
mutex_unlock(&ctx->mutex);
return r;
}
+int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size)
+{
+ int r;
+ mutex_lock(&ctx->scratch_mutex);
+ r = atom_execute_table_scratch_unlocked(ctx, index, params, params_size);
+ mutex_unlock(&ctx->scratch_mutex);
+ return r;
+}
+
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
static void atom_index_iio(struct atom_context *ctx, int base)
@@ -1265,14 +1293,14 @@ struct atom_context *atom_parse(struct card_info *card, void *bios)
ctx->bios = bios;
if (CU16(0) != ATOM_BIOS_MAGIC) {
- printk(KERN_INFO "Invalid BIOS magic.\n");
+ pr_info("Invalid BIOS magic\n");
kfree(ctx);
return NULL;
}
if (strncmp
(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
strlen(ATOM_ATI_MAGIC))) {
- printk(KERN_INFO "Invalid ATI magic.\n");
+ pr_info("Invalid ATI magic\n");
kfree(ctx);
return NULL;
}
@@ -1281,7 +1309,7 @@ struct atom_context *atom_parse(struct card_info *card, void *bios)
if (strncmp
(CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
strlen(ATOM_ROM_MAGIC))) {
- printk(KERN_INFO "Invalid ATOM magic.\n");
+ pr_info("Invalid ATOM magic\n");
kfree(ctx);
return NULL;
}
@@ -1305,7 +1333,7 @@ struct atom_context *atom_parse(struct card_info *card, void *bios)
break;
}
}
- printk(KERN_INFO "ATOM BIOS: %s\n", name);
+ pr_info("ATOM BIOS: %s\n", name);
return ctx;
}
@@ -1326,7 +1354,7 @@ int atom_asic_init(struct atom_context *ctx)
if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
return 1;
- ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps);
+ ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps, 16);
if (ret)
return ret;
@@ -1334,7 +1362,7 @@ int atom_asic_init(struct atom_context *ctx)
if (rdev->family < CHIP_R600) {
if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL))
- atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps);
+ atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps, 16);
}
return ret;
}
@@ -1346,8 +1374,8 @@ void atom_destroy(struct atom_context *ctx)
}
bool atom_parse_data_header(struct atom_context *ctx, int index,
- uint16_t * size, uint8_t * frev, uint8_t * crev,
- uint16_t * data_start)
+ uint16_t *size, uint8_t *frev, uint8_t *crev,
+ uint16_t *data_start)
{
int offset = index * 2 + 4;
int idx = CU16(ctx->data_table + offset);
@@ -1366,8 +1394,8 @@ bool atom_parse_data_header(struct atom_context *ctx, int index,
return true;
}
-bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
- uint8_t * crev)
+bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
+ uint8_t *crev)
{
int offset = index * 2 + 4;
int idx = CU16(ctx->cmd_table + offset);