Re: [PATCH 07/13] si2157: Briefly wait for tuning operation to complete

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 05/04/2019 05.29, Sean Young wrote:
> On Sat, Dec 29, 2018 at 11:51:16AM -0600, Brad Love wrote:
>> Some software reports no signal found on a frequency due to immediately
>> checking for lock as soon as set_params returns. This waits up 40ms for
>> tuning operation, then from 30-150ms (dig/analog) for signal lock before
>> returning from set_params and set_analog_params.
>>
>> Tuning typically completes in 20-30ms. Digital tuning will additionally
>> wait depending on signal characteristics. Analog tuning will wait the
>> full timeout in case of no signal.
> This looks like a workaround for broken userspace. Very possibly this
> is software was tested on a different frontend which does wait for tuning
> to complete.
>
> This is a change in uapi and will have to be done for all frontends, and
> documented. However I doubt such a change is acceptable.
>
> What software are you refering to?


Hi Sean,

I would have to check with support to find out the various software that
expect when a tune command returns for that tuning operation to have
actually completed. In the current state when you tune si2157 it
immediately returns, no care of the tuning operation completion, no care
of the pll lock success. This is correct? Not so according to Silicon
Labs documentation, which suggests a brief wait. I just took a look at
other drivers, sampling only those with set_analog_params, all but two
have similar code in place to actually allow the tune operation time to
complete (both digital and analog) before returning to userland. The
other drivers just insert arbitrary time delays to accommodate the
operations completion time. At least with my patch I am monitoring the
hardware to know when the operation actually completes.

I see in tuners (not frontends):

mt2063 - waits up to 100ms for lock status and return
r820t - sleep 100ms for pll lock status and return
tda827x - 170-500ms wait after tune before checking status and return
tda8290 - sleep 100ms up to 3x while checking tune status and return
tuner-xc2028 - sleep for 110ms awaiting lock status and return
xc4000 - 10ms sleep after tune, unless debug, then 100ms and return
xc5000 - 20ms sleep after tune,  if pll not locked, re-tune and sleep
again, repeat until success and return

There's also other arbitrary sleeps peppered throughout the operations.

Then you have si2157 that fires off the tuning commands and goes right
back to userland immediately, when with instrumented testing, the
operation takes time to complete and lock. The operation does not happen
instantaneously. Software that expects clocks to be locked when the
function returns determine this is an error. They query the tuner
immediately when tune returns and they output tuning failed.

Please explain why awaiting the hardware to say the "tuning operation
you requested is done and clocks are locked" is not ok. If it's not ok,
fine, but then a lot of other drivers are currently "not ok" as well.

Regards,

Brad


>
>
> Sean
>
>> Signed-off-by: Brad Love <brad@xxxxxxxxxxxxxxxx>
>> ---
>>  drivers/media/tuners/si2157.c | 87 +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 87 insertions(+)
>>
>> diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
>> index ff462ba..1737007 100644
>> --- a/drivers/media/tuners/si2157.c
>> +++ b/drivers/media/tuners/si2157.c
>> @@ -318,6 +318,89 @@ static int si2157_sleep(struct dvb_frontend *fe)
>>  	return ret;
>>  }
>>  
>> +static int si2157_tune_wait(struct i2c_client *client, u8 is_digital)
>> +{
>> +#define TUN_TIMEOUT 40
>> +#define DIG_TIMEOUT 30
>> +#define ANALOG_TIMEOUT 150
>> +	struct si2157_dev *dev = i2c_get_clientdata(client);
>> +	int ret;
>> +	unsigned long timeout;
>> +	unsigned long start_time;
>> +	u8 wait_status;
>> +	u8  tune_lock_mask;
>> +
>> +	if (is_digital)
>> +		tune_lock_mask = 0x04;
>> +	else
>> +		tune_lock_mask = 0x02;
>> +
>> +	mutex_lock(&dev->i2c_mutex);
>> +
>> +	/* wait tuner command complete */
>> +	start_time = jiffies;
>> +	timeout = start_time + msecs_to_jiffies(TUN_TIMEOUT);
>> +	while (!time_after(jiffies, timeout)) {
>> +		ret = i2c_master_recv(client, &wait_status,
>> +					sizeof(wait_status));
>> +		if (ret < 0) {
>> +			goto err_mutex_unlock;
>> +		} else if (ret != sizeof(wait_status)) {
>> +			ret = -EREMOTEIO;
>> +			goto err_mutex_unlock;
>> +		}
>> +
>> +		/* tuner done? */
>> +		if ((wait_status & 0x81) == 0x81)
>> +			break;
>> +		usleep_range(5000, 10000);
>> +	}
>> +
>> +	dev_dbg(&client->dev, "tuning took %d ms, status=0x%x\n",
>> +		jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
>> +		wait_status);
>> +
>> +	/* if we tuned ok, wait a bit for tuner lock */
>> +	if ((wait_status & 0x81) == 0x81) {
>> +		if (is_digital)
>> +			timeout = jiffies + msecs_to_jiffies(DIG_TIMEOUT);
>> +		else
>> +			timeout = jiffies + msecs_to_jiffies(ANALOG_TIMEOUT);
>> +		while (!time_after(jiffies, timeout)) {
>> +			ret = i2c_master_recv(client, &wait_status,
>> +						sizeof(wait_status));
>> +			if (ret < 0) {
>> +				goto err_mutex_unlock;
>> +			} else if (ret != sizeof(wait_status)) {
>> +				ret = -EREMOTEIO;
>> +				goto err_mutex_unlock;
>> +			}
>> +
>> +			/* tuner locked? */
>> +			if (wait_status & tune_lock_mask)
>> +				break;
>> +			usleep_range(5000, 10000);
>> +		}
>> +	}
>> +
>> +	dev_dbg(&client->dev, "tuning+lock took %d ms, status=0x%x\n",
>> +		jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
>> +		wait_status);
>> +
>> +	if ((wait_status & 0xc0) != 0x80) {
>> +		ret = -ETIMEDOUT;
>> +		goto err_mutex_unlock;
>> +	}
>> +
>> +	mutex_unlock(&dev->i2c_mutex);
>> +	return 0;
>> +
>> +err_mutex_unlock:
>> +	mutex_unlock(&dev->i2c_mutex);
>> +	dev_dbg(&client->dev, "failed=%d\n", ret);
>> +	return ret;
>> +}
>> +
>>  static int si2157_set_params(struct dvb_frontend *fe)
>>  {
>>  	struct i2c_client *client = fe->tuner_priv;
>> @@ -417,6 +500,8 @@ static int si2157_set_params(struct dvb_frontend *fe)
>>  	dev->bandwidth = bandwidth;
>>  	dev->frequency = c->frequency;
>>  
>> +	si2157_tune_wait(client, 1); /* wait to complete, ignore any errors */
>> +
>>  	return 0;
>>  err:
>>  	dev->bandwidth = 0;
>> @@ -626,6 +711,8 @@ static int si2157_set_analog_params(struct dvb_frontend *fe,
>>  #endif
>>  	dev->bandwidth = bandwidth;
>>  
>> +	si2157_tune_wait(client, 0); /* wait to complete, ignore any errors */
>> +
>>  	return 0;
>>  err:
>>  	dev->bandwidth = 0;
>> -- 
>> 2.7.4





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux