Hi Mauro,

Am 10.01.2010 15:15, schrieb Mauro Carvalho Chehab:
Andreas Regel wrote:
Hi Mauro,

Am 10.01.2010 13:52, schrieb Mauro Carvalho Chehab:
Manu Abraham wrote:
Mauro,

Please pull http://jusst.de/hg/stv090x changesets: from 13880 - 13891
inclusive of both.

The third changeset has some locking troubles:

# Node ID 4dd17a6a5ecc320eab58590a8567e5ba03b9d53a
[STV090x] Added mutex protection around tuner I2C access.

After the patch, the code will look like:

static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
          struct stv090x_state *state = fe->demodulator_priv;
          u32 reg;

          if (enable)
                  mutex_lock(&state->internal->tuner_lock);

          reg = STV090x_READ_DEMOD(state, I2CRPT);
          if (enable) {
                  dprintk(FE_DEBUG, 1, "Enable Gate");
                  STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
                  if (STV090x_WRITE_DEMOD(state, I2CRPT, reg)<   0)
                          goto err;

          } else {

                  dprintk(FE_DEBUG, 1, "Disable Gate");
                  STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
                  if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg))<   0)
                          goto err;
          }

          if (!enable)
                  mutex_unlock(&state->internal->tuner_lock);

          return 0;
err:
          dprintk(FE_ERROR, 1, "I/O error");
          mutex_unlock(&state->internal->tuner_lock);
          return -1;
}

As the err: is called on both enable and disable conditions, the error
code will try to unlock an already unlocked mutex, if !enable.

Also, it doesn't make sense to lock only if the gate is enabled,
since it seems that the lock is meant to protect the i2c gate bus and
both conditions will call STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD,
enable ? 1 : 0);

The better would be simply to remove the if (enable)/if (!enable) tests
on the above code.

The lock shall protect the access to the tuners and not to the registers
itself, so it is locked when enable is set and unlocked when enable isn't

Ok.

The code between a call to stv090x_i2c_gate_ctrl(..., 1)
and stv090x_i2c_gate_ctrl(..., 0) shall be exclusive in case both tuners
have the same I2C address.

By just looking at the i2c_gate_ctrl, it is not clear how do you expect that
the locking will work. You should add a comment better explaining it.

Also, as I pointed, if STV090x_WRITE_DEMOD fails, the unlock code will be called
even if the gate is not enabled.


you don't have to look at stv090x_i2c_gate_ctrl alone. stv090x driver contains code like this:

        if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
                goto err;

        tuner access

        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
                goto err;

Intention of the patch is to make the tuner access exclusive. Thats the reason why the mutex is locked when gate is opened and unlocked when the gate is closed.

In case the opening fails the close call is not made und thus mutex is not unlocked twice.

There one problem pending with: when there is an error during "tuner access" the gate will not be closed and thus the mutex will not be unlocked. For this case a patch from Oliver Endriss is attached.

Regards,
Andreas
# HG changeset patch
# User Oliver Endriss <o.endr...@gmx.de>
# Date 1263097942 -3600
# Node ID fefb0eb3c442f8ab1e446c6f275c914a99495312
# Parent  b1e950fefc1ac04f3ef67d274d6a72859afd734f
stv090x: Disable I2C gate on error

From: Oliver Endriss <o.endr...@gmx.de>

The I2C gate must also be disabled, if a tuner command failed.
Otherwise the tuner mutex would be locked forever.

Priority: normal

Signed-off-by: Oliver Endriss <o.endr...@gmx.de>

diff -r b1e950fefc1a -r fefb0eb3c442 linux/drivers/media/dvb/frontends/stv090x.c
--- a/linux/drivers/media/dvb/frontends/stv090x.c       Wed Jan 06 02:24:56 
2010 +0400
+++ b/linux/drivers/media/dvb/frontends/stv090x.c       Sun Jan 10 05:32:22 
2010 +0100
@@ -2514,12 +2514,12 @@ static u32 stv090x_srate_srch_coarse(str
 
                        if (state->config->tuner_set_frequency) {
                                if (state->config->tuner_set_frequency(fe, 
freq) < 0)
-                                       goto err;
+                                       goto err_gateoff;
                        }
 
                        if (state->config->tuner_set_bandwidth) {
                                if (state->config->tuner_set_bandwidth(fe, 
state->tuner_bw) < 0)
-                                       goto err;
+                                       goto err_gateoff;
                        }
 
                        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2532,7 +2532,7 @@ static u32 stv090x_srate_srch_coarse(str
 
                        if (state->config->tuner_get_status) {
                                if (state->config->tuner_get_status(fe, &reg) < 
0)
-                                       goto err;
+                                       goto err_gateoff;
                        }
 
                        if (reg)
@@ -2551,6 +2551,9 @@ static u32 stv090x_srate_srch_coarse(str
                srate_coarse = stv090x_get_srate(state, state->internal->mclk);
 
        return srate_coarse;
+
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
@@ -2899,12 +2902,12 @@ static int stv090x_get_coldlock(struct s
 
                                        if (state->config->tuner_set_frequency) 
{
                                                if 
(state->config->tuner_set_frequency(fe, freq) < 0)
-                                                       goto err;
+                                                       goto err_gateoff;
                                        }
 
                                        if (state->config->tuner_set_bandwidth) 
{
                                                if 
(state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-                                                       goto err;
+                                                       goto err_gateoff;
                                        }
 
                                        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2917,7 +2920,7 @@ static int stv090x_get_coldlock(struct s
 
                                        if (state->config->tuner_get_status) {
                                                if 
(state->config->tuner_get_status(fe, &reg) < 0)
-                                                       goto err;
+                                                       goto err_gateoff;
                                        }
 
                                        if (reg)
@@ -2948,6 +2951,8 @@ static int stv090x_get_coldlock(struct s
 
        return lock;
 
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
@@ -3321,7 +3326,7 @@ static enum stv090x_signal_state stv090x
 
        if (state->config->tuner_get_frequency) {
                if (state->config->tuner_get_frequency(fe, &state->frequency) < 
0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -3349,7 +3354,7 @@ static enum stv090x_signal_state stv090x
 
                if (state->config->tuner_get_frequency) {
                        if (state->config->tuner_get_frequency(fe, 
&state->frequency) < 0)
-                               goto err;
+                               goto err_gateoff;
                }
 
                if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -3369,6 +3374,9 @@ static enum stv090x_signal_state stv090x
        }
 
        return STV090x_OUTOFRANGE;
+
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
@@ -3735,7 +3743,7 @@ static int stv090x_optimize_track(struct
 
                                if (state->config->tuner_set_bandwidth) {
                                        if 
(state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-                                               goto err;
+                                               goto err_gateoff;
                                }
 
                                if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -3787,6 +3795,9 @@ static int stv090x_optimize_track(struct
                stv090x_set_vit_thtracq(state);
 
        return 0;
+
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
@@ -4042,17 +4053,17 @@ static enum stv090x_signal_state stv090x
 
        if (state->config->tuner_set_bbgain) {
                if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (state->config->tuner_set_frequency) {
                if (state->config->tuner_set_frequency(fe, state->frequency) < 
0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (state->config->tuner_set_bandwidth) {
                if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -4065,7 +4076,7 @@ static enum stv090x_signal_state stv090x
 
        if (state->config->tuner_get_status) {
                if (state->config->tuner_get_status(fe, &reg) < 0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (reg)
@@ -4198,6 +4209,8 @@ static enum stv090x_signal_state stv090x
        }
        return signal_state;
 
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
@@ -5138,12 +5151,12 @@ static int stv090x_init(struct dvb_front
 
        if (config->tuner_set_mode) {
                if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (config->tuner_init) {
                if (config->tuner_init(fe) < 0)
-                       goto err;
+                       goto err_gateoff;
        }
 
        if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -5153,6 +5166,9 @@ static int stv090x_init(struct dvb_front
                goto err;
 
        return 0;
+
+err_gateoff:
+       stv090x_i2c_gate_ctrl(fe, 0);
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;

Reply via email to