| From 5ac64ba12aca3bef18e61c866583155a3bbf81c4 Mon Sep 17 00:00:00 2001 |
| From: Mauro Carvalho Chehab <m.chehab@samsung.com> |
| Date: Fri, 13 Dec 2013 10:35:03 -0300 |
| Subject: [media] dib8000: make 32 bits read atomic |
| |
| From: Mauro Carvalho Chehab <m.chehab@samsung.com> |
| |
| commit 5ac64ba12aca3bef18e61c866583155a3bbf81c4 upstream. |
| |
| As the dvb-frontend kthread can be called anytime, it can race |
| with some get status ioctl. So, it seems better to avoid one to |
| race with the other while reading a 32 bits register. |
| I can't see any other reason for having a mutex there at I2C, except |
| to provide such kind of protection, as the I2C core already has a |
| mutex to protect I2C transfers. |
| |
| Note: instead of this approach, it could eventually remove the dib8000 |
| specific mutex for it, and either group the 4 ops into one xfer or |
| to manually control the I2C mutex. The main advantage of the current |
| approach is that the changes are smaller and more puntual. |
| |
| Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com> |
| Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com> |
| Acked-by: Patrick Boettcher <pboettcher@kernellabs.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/media/dvb-frontends/dib8000.c | 33 +++++++++++++++++++++++++-------- |
| 1 file changed, 25 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/media/dvb-frontends/dib8000.c |
| +++ b/drivers/media/dvb-frontends/dib8000.c |
| @@ -157,15 +157,10 @@ static u16 dib8000_i2c_read16(struct i2c |
| return ret; |
| } |
| |
| -static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) |
| +static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) |
| { |
| u16 ret; |
| |
| - if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { |
| - dprintk("could not acquire lock"); |
| - return 0; |
| - } |
| - |
| state->i2c_write_buffer[0] = reg >> 8; |
| state->i2c_write_buffer[1] = reg & 0xff; |
| |
| @@ -183,6 +178,21 @@ static u16 dib8000_read_word(struct dib8 |
| dprintk("i2c read error on %d", reg); |
| |
| ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; |
| + |
| + return ret; |
| +} |
| + |
| +static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) |
| +{ |
| + u16 ret; |
| + |
| + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { |
| + dprintk("could not acquire lock"); |
| + return 0; |
| + } |
| + |
| + ret = __dib8000_read_word(state, reg); |
| + |
| mutex_unlock(&state->i2c_buffer_lock); |
| |
| return ret; |
| @@ -192,8 +202,15 @@ static u32 dib8000_read32(struct dib8000 |
| { |
| u16 rw[2]; |
| |
| - rw[0] = dib8000_read_word(state, reg + 0); |
| - rw[1] = dib8000_read_word(state, reg + 1); |
| + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { |
| + dprintk("could not acquire lock"); |
| + return 0; |
| + } |
| + |
| + rw[0] = __dib8000_read_word(state, reg + 0); |
| + rw[1] = __dib8000_read_word(state, reg + 1); |
| + |
| + mutex_unlock(&state->i2c_buffer_lock); |
| |
| return ((rw[0] << 16) | (rw[1])); |
| } |