Commit 50785403 authored by Dave Airlie's avatar Dave Airlie Committed by Luis Henriques

drm/radeon: add locking around atombios scratch space usage

commit 1c949842 upstream.

While developing MST support I noticed I often got the wrong data
back from a transaction, in a racy fashion. I noticed the scratch
space wasn't locked against concurrent users.

Based on a patch by Alex, but I've made it a bit more obvious when
things are locked.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 1d759cc6
...@@ -1217,7 +1217,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 ...@@ -1217,7 +1217,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
return ret; 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 r; int r;
...@@ -1238,6 +1238,15 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) ...@@ -1238,6 +1238,15 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
return r; return r;
} }
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
{
int r;
mutex_lock(&ctx->scratch_mutex);
r = atom_execute_table_scratch_unlocked(ctx, index, params);
mutex_unlock(&ctx->scratch_mutex);
return r;
}
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 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) static void atom_index_iio(struct atom_context *ctx, int base)
......
...@@ -125,6 +125,7 @@ struct card_info { ...@@ -125,6 +125,7 @@ struct card_info {
struct atom_context { struct atom_context {
struct card_info *card; struct card_info *card;
struct mutex mutex; struct mutex mutex;
struct mutex scratch_mutex;
void *bios; void *bios;
uint32_t cmd_table, data_table; uint32_t cmd_table, data_table;
uint16_t *iio; uint16_t *iio;
...@@ -145,6 +146,7 @@ extern int atom_debug; ...@@ -145,6 +146,7 @@ extern int atom_debug;
struct atom_context *atom_parse(struct card_info *, void *); struct atom_context *atom_parse(struct card_info *, void *);
int atom_execute_table(struct atom_context *, int, uint32_t *); int atom_execute_table(struct atom_context *, int, uint32_t *);
int atom_execute_table_scratch_unlocked(struct atom_context *, int, uint32_t *);
int atom_asic_init(struct atom_context *); int atom_asic_init(struct atom_context *);
void atom_destroy(struct atom_context *); void atom_destroy(struct atom_context *);
bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size,
......
...@@ -100,6 +100,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -100,6 +100,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex); mutex_lock(&chan->mutex);
mutex_lock(&rdev->mode_info.atom_context->scratch_mutex);
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
...@@ -113,7 +114,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -113,7 +114,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
if (ASIC_IS_DCE4(rdev)) if (ASIC_IS_DCE4(rdev))
args.v2.ucHPD_ID = chan->rec.hpd; args.v2.ucHPD_ID = chan->rec.hpd;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args);
*ack = args.v1.ucReplyStatus; *ack = args.v1.ucReplyStatus;
...@@ -147,6 +148,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -147,6 +148,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
r = recv_bytes; r = recv_bytes;
done: done:
mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex);
mutex_unlock(&chan->mutex); mutex_unlock(&chan->mutex);
return r; return r;
......
...@@ -48,6 +48,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -48,6 +48,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex); mutex_lock(&chan->mutex);
mutex_lock(&rdev->mode_info.atom_context->scratch_mutex);
base = (unsigned char *)rdev->mode_info.atom_context->scratch; base = (unsigned char *)rdev->mode_info.atom_context->scratch;
...@@ -82,7 +83,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -82,7 +83,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
args.ucSlaveAddr = slave_addr << 1; args.ucSlaveAddr = slave_addr << 1;
args.ucLineNumber = chan->rec.i2c_id; args.ucLineNumber = chan->rec.i2c_id;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args);
/* error */ /* error */
if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
...@@ -95,6 +96,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -95,6 +96,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
radeon_atom_copy_swap(buf, base, num, false); radeon_atom_copy_swap(buf, base, num, false);
done: done:
mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex);
mutex_unlock(&chan->mutex); mutex_unlock(&chan->mutex);
return r; return r;
......
...@@ -902,6 +902,7 @@ int radeon_atombios_init(struct radeon_device *rdev) ...@@ -902,6 +902,7 @@ int radeon_atombios_init(struct radeon_device *rdev)
} }
mutex_init(&rdev->mode_info.atom_context->mutex); mutex_init(&rdev->mode_info.atom_context->mutex);
mutex_init(&rdev->mode_info.atom_context->scratch_mutex);
radeon_atom_initialize_bios_scratch_regs(rdev->ddev); radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
atom_allocate_fb_scratch(rdev->mode_info.atom_context); atom_allocate_fb_scratch(rdev->mode_info.atom_context);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment