| From 18c63bfc51b471d518a9a8c6cf589e65bc90d213 Mon Sep 17 00:00:00 2001 |
| From: James Hutchinson <jahutchinson99@googlemail.com> |
| Date: Sun, 13 Jan 2019 16:13:47 -0500 |
| Subject: media: m88ds3103: serialize reset messages in m88ds3103_set_frontend |
| |
| [ Upstream commit 981fbe3da20a6f35f17977453bce7dfc1664d74f ] |
| |
| Ref: https://bugzilla.kernel.org/show_bug.cgi?id=199323 |
| |
| Users are experiencing problems with the DVBSky S960/S960C USB devices |
| since the following commit: |
| |
| 9d659ae: ("locking/mutex: Add lock handoff to avoid starvation") |
| |
| The device malfunctions after running for an indeterminable period of |
| time, and the problem can only be cleared by rebooting the machine. |
| |
| It is possible to encourage the problem to surface by blocking the |
| signal to the LNB. |
| |
| Further debugging revealed the cause of the problem. |
| |
| In the following capture: |
| - thread #1325 is running m88ds3103_set_frontend |
| - thread #42 is running ts2020_stat_work |
| |
| a> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 80 |
| [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 08 |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 3d |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff |
| b> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 00 |
| [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 21 |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 66 |
| [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff |
| [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 |
| [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 60 02 10 0b |
| [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 |
| |
| Two i2c messages are sent to perform a reset in m88ds3103_set_frontend: |
| |
| a. 0x07, 0x80 |
| b. 0x07, 0x00 |
| |
| However, as shown in the capture, the regmap mutex is being handed over |
| to another thread (ts2020_stat_work) in between these two messages. |
| |
| >From here, the device responds to every i2c message with an 07 message, |
| and will only return to normal operation following a power cycle. |
| |
| Use regmap_multi_reg_write to group the two reset messages, ensuring |
| both are processed before the regmap mutex is unlocked. |
| |
| Signed-off-by: James Hutchinson <jahutchinson99@googlemail.com> |
| Reviewed-by: Antti Palosaari <crope@iki.fi> |
| Signed-off-by: Sean Young <sean@mess.org> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/media/dvb-frontends/m88ds3103.c | 9 ++++----- |
| 1 file changed, 4 insertions(+), 5 deletions(-) |
| |
| diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c |
| index 123f2a33738b0..403f42806455e 100644 |
| --- a/drivers/media/dvb-frontends/m88ds3103.c |
| +++ b/drivers/media/dvb-frontends/m88ds3103.c |
| @@ -309,6 +309,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) |
| u16 u16tmp; |
| u32 tuner_frequency_khz, target_mclk; |
| s32 s32tmp; |
| + static const struct reg_sequence reset_buf[] = { |
| + {0x07, 0x80}, {0x07, 0x00} |
| + }; |
| |
| dev_dbg(&client->dev, |
| "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", |
| @@ -321,11 +324,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) |
| } |
| |
| /* reset */ |
| - ret = regmap_write(dev->regmap, 0x07, 0x80); |
| - if (ret) |
| - goto err; |
| - |
| - ret = regmap_write(dev->regmap, 0x07, 0x00); |
| + ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2); |
| if (ret) |
| goto err; |
| |
| -- |
| 2.20.1 |
| |