diff mbox series

rtw88: Add delay on polling h2c command status bit

Message ID 20200406093623.3980-1-kai.heng.feng@canonical.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series rtw88: Add delay on polling h2c command status bit | expand

Commit Message

Kai-Heng Feng April 6, 2020, 9:36 a.m. UTC
On some systems we can constanly see rtw88 complains:
[39584.721375] rtw_pci 0000:03:00.0: failed to send h2c command

Increase interval of each check to wait the status bit really changes.

While at it, add some helpers so we can use standarized
readx_poll_timeout() macro.

Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/net/wireless/realtek/rtw88/fw.c  | 12 ++++++------
 drivers/net/wireless/realtek/rtw88/hci.h |  4 ++++
 2 files changed, 10 insertions(+), 6 deletions(-)

Comments

Tony Chuang April 6, 2020, 11:01 a.m. UTC | #1
> Subject: [PATCH] rtw88: Add delay on polling h2c command status bit
> 
> On some systems we can constanly see rtw88 complains:
> [39584.721375] rtw_pci 0000:03:00.0: failed to send h2c command
> 
> Increase interval of each check to wait the status bit really changes.
> 
> While at it, add some helpers so we can use standarized
> readx_poll_timeout() macro.
> 
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
>  drivers/net/wireless/realtek/rtw88/fw.c  | 12 ++++++------
>  drivers/net/wireless/realtek/rtw88/hci.h |  4 ++++
>  2 files changed, 10 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/fw.c
> b/drivers/net/wireless/realtek/rtw88/fw.c
> index 05c430b3489c..bc9982e77524 100644
> --- a/drivers/net/wireless/realtek/rtw88/fw.c
> +++ b/drivers/net/wireless/realtek/rtw88/fw.c
> @@ -2,6 +2,8 @@
>  /* Copyright(c) 2018-2019  Realtek Corporation
>   */
> 
> +#include <linux/iopoll.h>
> +
>  #include "main.h"
>  #include "coex.h"
>  #include "fw.h"
> @@ -193,8 +195,8 @@ static void rtw_fw_send_h2c_command(struct
> rtw_dev *rtwdev,
>  	u8 box;
>  	u8 box_state;
>  	u32 box_reg, box_ex_reg;
> -	u32 h2c_wait;
>  	int idx;
> +	int ret;
> 
>  	rtw_dbg(rtwdev, RTW_DBG_FW,
>  		"send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n",
> @@ -226,12 +228,10 @@ static void rtw_fw_send_h2c_command(struct
> rtw_dev *rtwdev,
>  		goto out;
>  	}
> 
> -	h2c_wait = 20;
> -	do {
> -		box_state = rtw_read8(rtwdev, REG_HMETFR);
> -	} while ((box_state >> box) & 0x1 && --h2c_wait > 0);
> +	ret = readx_poll_timeout(rr8, REG_HMETFR, box_state,
> +				 !((box_state >> box) & 0x1), 100, 3000);
> 
> -	if (!h2c_wait) {
> +	if (ret) {
>  		rtw_err(rtwdev, "failed to send h2c command\n");
>  		goto out;
>  	}
> diff --git a/drivers/net/wireless/realtek/rtw88/hci.h
> b/drivers/net/wireless/realtek/rtw88/hci.h
> index 2cba327e6218..24062c7079c6 100644
> --- a/drivers/net/wireless/realtek/rtw88/hci.h
> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr,
> u32 mask, u8 data)
>  	rtw_write8(rtwdev, addr, set);
>  }
> 
> +#define rr8(addr)      rtw_read8(rtwdev, addr)
> +#define rr16(addr)     rtw_read16(rtwdev, addr)
> +#define rr32(addr)     rtw_read32(rtwdev, addr)
> +
>  static inline enum rtw_hci_type rtw_hci_type(struct rtw_dev *rtwdev)
>  {
>  	return rtwdev->hci.type;
> --

I think the timeout is because the H2C is triggered when the lower 4 bytes are written.
So, we probably should write h2c[4] ~ h2c[7] before h2c[0] ~ h2c[3].

But this delay still works, I think you can keep it, and reorder the h2c write sequence.

Yen-Hsuan
Kai-Heng Feng April 6, 2020, 11:56 a.m. UTC | #2
Hi Tony,

> On Apr 6, 2020, at 19:01, Tony Chuang <yhchuang@realtek.com> wrote:
> 
>> Subject: [PATCH] rtw88: Add delay on polling h2c command status bit
>> 
>> On some systems we can constanly see rtw88 complains:
>> [39584.721375] rtw_pci 0000:03:00.0: failed to send h2c command
>> 
>> Increase interval of each check to wait the status bit really changes.
>> 
>> While at it, add some helpers so we can use standarized
>> readx_poll_timeout() macro.
>> 
>> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>> ---
>> drivers/net/wireless/realtek/rtw88/fw.c  | 12 ++++++------
>> drivers/net/wireless/realtek/rtw88/hci.h |  4 ++++
>> 2 files changed, 10 insertions(+), 6 deletions(-)
>> 
>> diff --git a/drivers/net/wireless/realtek/rtw88/fw.c
>> b/drivers/net/wireless/realtek/rtw88/fw.c
>> index 05c430b3489c..bc9982e77524 100644
>> --- a/drivers/net/wireless/realtek/rtw88/fw.c
>> +++ b/drivers/net/wireless/realtek/rtw88/fw.c
>> @@ -2,6 +2,8 @@
>> /* Copyright(c) 2018-2019  Realtek Corporation
>>  */
>> 
>> +#include <linux/iopoll.h>
>> +
>> #include "main.h"
>> #include "coex.h"
>> #include "fw.h"
>> @@ -193,8 +195,8 @@ static void rtw_fw_send_h2c_command(struct
>> rtw_dev *rtwdev,
>> 	u8 box;
>> 	u8 box_state;
>> 	u32 box_reg, box_ex_reg;
>> -	u32 h2c_wait;
>> 	int idx;
>> +	int ret;
>> 
>> 	rtw_dbg(rtwdev, RTW_DBG_FW,
>> 		"send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n",
>> @@ -226,12 +228,10 @@ static void rtw_fw_send_h2c_command(struct
>> rtw_dev *rtwdev,
>> 		goto out;
>> 	}
>> 
>> -	h2c_wait = 20;
>> -	do {
>> -		box_state = rtw_read8(rtwdev, REG_HMETFR);
>> -	} while ((box_state >> box) & 0x1 && --h2c_wait > 0);
>> +	ret = readx_poll_timeout(rr8, REG_HMETFR, box_state,
>> +				 !((box_state >> box) & 0x1), 100, 3000);
>> 
>> -	if (!h2c_wait) {
>> +	if (ret) {
>> 		rtw_err(rtwdev, "failed to send h2c command\n");
>> 		goto out;
>> 	}
>> diff --git a/drivers/net/wireless/realtek/rtw88/hci.h
>> b/drivers/net/wireless/realtek/rtw88/hci.h
>> index 2cba327e6218..24062c7079c6 100644
>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr,
>> u32 mask, u8 data)
>> 	rtw_write8(rtwdev, addr, set);
>> }
>> 
>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
>> +
>> static inline enum rtw_hci_type rtw_hci_type(struct rtw_dev *rtwdev)
>> {
>> 	return rtwdev->hci.type;
>> --
> 
> I think the timeout is because the H2C is triggered when the lower 4 bytes are written.
> So, we probably should write h2c[4] ~ h2c[7] before h2c[0] ~ h2c[3].

I can still see "failed to send h2c command" with the following patch:

diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index eb7e623c811a..a296c860045f 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -240,10 +240,10 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
                goto out;
        }

-       for (idx = 0; idx < 4; idx++)
-               rtw_write8(rtwdev, box_reg + idx, h2c[idx]);
        for (idx = 0; idx < 4; idx++)
                rtw_write8(rtwdev, box_ex_reg + idx, h2c[idx + 4]);
+       for (idx = 0; idx < 4; idx++)
+               rtw_write8(rtwdev, box_reg + idx, h2c[idx]);

        if (++rtwdev->h2c.last_box_num >= 4)
                rtwdev->h2c.last_box_num = 0;


> 
> But this delay still works, I think you can keep it, and reorder the h2c write sequence.
> 
> Yen-Hsuan
Kalle Valo April 6, 2020, 12:17 p.m. UTC | #3
Kai-Heng Feng <kai.heng.feng@canonical.com> writes:

> On some systems we can constanly see rtw88 complains:
> [39584.721375] rtw_pci 0000:03:00.0: failed to send h2c command
>
> Increase interval of each check to wait the status bit really changes.
>
> While at it, add some helpers so we can use standarized
> readx_poll_timeout() macro.

One logical change per patch, please.

> --- a/drivers/net/wireless/realtek/rtw88/hci.h
> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u8 data)
>  	rtw_write8(rtwdev, addr, set);
>  }
>  
> +#define rr8(addr)      rtw_read8(rtwdev, addr)
> +#define rr16(addr)     rtw_read16(rtwdev, addr)
> +#define rr32(addr)     rtw_read32(rtwdev, addr)

For me these macros reduce code readability, not improve anything. They
hide the use of rtwdev variable, which is evil, and a name like rr8() is
just way too vague. Please keep the original function names as is.
Kai-Heng Feng April 6, 2020, 1:18 p.m. UTC | #4
> On Apr 6, 2020, at 20:17, Kalle Valo <kvalo@codeaurora.org> wrote:
> 
> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
> 
>> On some systems we can constanly see rtw88 complains:
>> [39584.721375] rtw_pci 0000:03:00.0: failed to send h2c command
>> 
>> Increase interval of each check to wait the status bit really changes.
>> 
>> While at it, add some helpers so we can use standarized
>> readx_poll_timeout() macro.
> 
> One logical change per patch, please.

Will split it into two separate patches.

> 
>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u8 data)
>> 	rtw_write8(rtwdev, addr, set);
>> }
>> 
>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
> 
> For me these macros reduce code readability, not improve anything. They
> hide the use of rtwdev variable, which is evil, and a name like rr8() is
> just way too vague. Please keep the original function names as is.

The inspiration is from another driver.
readx_poll_timeout macro only takes one argument for the op.
Some other drivers have their own poll_timeout implementation,
and I guess it makes sense to make one specific for rtw88.

Kai-Heng

> 
> -- 
> https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Kalle Valo April 6, 2020, 1:24 p.m. UTC | #5
Kai-Heng Feng <kai.heng.feng@canonical.com> writes:

>> On Apr 6, 2020, at 20:17, Kalle Valo <kvalo@codeaurora.org> wrote:
>> 
>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>> 
>>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32
>>> addr, u32 mask, u8 data)
>>> 	rtw_write8(rtwdev, addr, set);
>>> }
>>> 
>>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
>> 
>> For me these macros reduce code readability, not improve anything. They
>> hide the use of rtwdev variable, which is evil, and a name like rr8() is
>> just way too vague. Please keep the original function names as is.
>
> The inspiration is from another driver.
> readx_poll_timeout macro only takes one argument for the op.
> Some other drivers have their own poll_timeout implementation,
> and I guess it makes sense to make one specific for rtw88.

I'm not even understanding the problem you are tying to fix with these
macros. The upstream philosopyhy is to have the source code readable and
maintainable, not to use minimal number of characters. There's a reason
why we don't name our functions a(), b(), c() and so on.
Kai-Heng Feng April 6, 2020, 1:35 p.m. UTC | #6
> On Apr 6, 2020, at 21:24, Kalle Valo <kvalo@codeaurora.org> wrote:
> 
> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
> 
>>> On Apr 6, 2020, at 20:17, Kalle Valo <kvalo@codeaurora.org> wrote:
>>> 
>>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>>> 
>>>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>>>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>>>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32
>>>> addr, u32 mask, u8 data)
>>>> 	rtw_write8(rtwdev, addr, set);
>>>> }
>>>> 
>>>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>>>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>>>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
>>> 
>>> For me these macros reduce code readability, not improve anything. They
>>> hide the use of rtwdev variable, which is evil, and a name like rr8() is
>>> just way too vague. Please keep the original function names as is.
>> 
>> The inspiration is from another driver.
>> readx_poll_timeout macro only takes one argument for the op.
>> Some other drivers have their own poll_timeout implementation,
>> and I guess it makes sense to make one specific for rtw88.
> 
> I'm not even understanding the problem you are tying to fix with these
> macros. The upstream philosopyhy is to have the source code readable and
> maintainable, not to use minimal number of characters. There's a reason
> why we don't name our functions a(), b(), c() and so on.

The current h2c polling doesn't have delay between each interval, so the polling is too fast and the following logic considers it's a timeout.
The readx_poll_timeout() macro provides a generic mechanism to setup an interval delay and timeout which is what we need here.
However readx_poll_timeout only accepts one parameter which usually is memory address, while we need to pass both rtwdev and address.

So if hiding rtwdev is evil, we can roll our own variant of readx_poll_timeout() to make the polling readable.

Kai-Heng

> 
> -- 
> https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Kalle Valo April 6, 2020, 2:03 p.m. UTC | #7
Kai-Heng Feng <kai.heng.feng@canonical.com> writes:

>> On Apr 6, 2020, at 21:24, Kalle Valo <kvalo@codeaurora.org> wrote:
>> 
>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>> 
>>>> On Apr 6, 2020, at 20:17, Kalle Valo <kvalo@codeaurora.org> wrote:
>>>> 
>>>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>>>> 
>>>>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>>>>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>>>>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32
>>>>> addr, u32 mask, u8 data)
>>>>> 	rtw_write8(rtwdev, addr, set);
>>>>> }
>>>>> 
>>>>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>>>>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>>>>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
>>>> 
>>>> For me these macros reduce code readability, not improve anything. They
>>>> hide the use of rtwdev variable, which is evil, and a name like rr8() is
>>>> just way too vague. Please keep the original function names as is.
>>> 
>>> The inspiration is from another driver.
>>> readx_poll_timeout macro only takes one argument for the op.
>>> Some other drivers have their own poll_timeout implementation,
>>> and I guess it makes sense to make one specific for rtw88.
>> 
>> I'm not even understanding the problem you are tying to fix with these
>> macros. The upstream philosopyhy is to have the source code readable and
>> maintainable, not to use minimal number of characters. There's a reason
>> why we don't name our functions a(), b(), c() and so on.
>
> The current h2c polling doesn't have delay between each interval, so
> the polling is too fast and the following logic considers it's a
> timeout.
> The readx_poll_timeout() macro provides a generic mechanism to setup
> an interval delay and timeout which is what we need here.
> However readx_poll_timeout only accepts one parameter which usually is
> memory address, while we need to pass both rtwdev and address.
>
> So if hiding rtwdev is evil, we can roll our own variant of
> readx_poll_timeout() to make the polling readable.

Can't you do:

ret = read_poll_timeout(rtw_read8, box_state,
                        !((box_state >> box) & 0x1), 100,
                        3000, false, rtw_dev, REG_HMETFR);

No ugly macros needed and it should function the same. But I did not
test this in any way, so no idea if it even compiles.
Kai-Heng Feng April 7, 2020, 7:20 a.m. UTC | #8
> On Apr 6, 2020, at 22:03, Kalle Valo <kvalo@codeaurora.org> wrote:
> 
> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
> 
>>> On Apr 6, 2020, at 21:24, Kalle Valo <kvalo@codeaurora.org> wrote:
>>> 
>>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>>> 
>>>>> On Apr 6, 2020, at 20:17, Kalle Valo <kvalo@codeaurora.org> wrote:
>>>>> 
>>>>> Kai-Heng Feng <kai.heng.feng@canonical.com> writes:
>>>>> 
>>>>>> --- a/drivers/net/wireless/realtek/rtw88/hci.h
>>>>>> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
>>>>>> @@ -253,6 +253,10 @@ rtw_write8_mask(struct rtw_dev *rtwdev, u32
>>>>>> addr, u32 mask, u8 data)
>>>>>> 	rtw_write8(rtwdev, addr, set);
>>>>>> }
>>>>>> 
>>>>>> +#define rr8(addr)      rtw_read8(rtwdev, addr)
>>>>>> +#define rr16(addr)     rtw_read16(rtwdev, addr)
>>>>>> +#define rr32(addr)     rtw_read32(rtwdev, addr)
>>>>> 
>>>>> For me these macros reduce code readability, not improve anything. They
>>>>> hide the use of rtwdev variable, which is evil, and a name like rr8() is
>>>>> just way too vague. Please keep the original function names as is.
>>>> 
>>>> The inspiration is from another driver.
>>>> readx_poll_timeout macro only takes one argument for the op.
>>>> Some other drivers have their own poll_timeout implementation,
>>>> and I guess it makes sense to make one specific for rtw88.
>>> 
>>> I'm not even understanding the problem you are tying to fix with these
>>> macros. The upstream philosopyhy is to have the source code readable and
>>> maintainable, not to use minimal number of characters. There's a reason
>>> why we don't name our functions a(), b(), c() and so on.
>> 
>> The current h2c polling doesn't have delay between each interval, so
>> the polling is too fast and the following logic considers it's a
>> timeout.
>> The readx_poll_timeout() macro provides a generic mechanism to setup
>> an interval delay and timeout which is what we need here.
>> However readx_poll_timeout only accepts one parameter which usually is
>> memory address, while we need to pass both rtwdev and address.
>> 
>> So if hiding rtwdev is evil, we can roll our own variant of
>> readx_poll_timeout() to make the polling readable.
> 
> Can't you do:
> 
> ret = read_poll_timeout(rtw_read8, box_state,
>                        !((box_state >> box) & 0x1), 100,
>                        3000, false, rtw_dev, REG_HMETFR);
> 
> No ugly macros needed and it should function the same. But I did not
> test this in any way, so no idea if it even compiles.

Yes that will do. Didn't notice the recently added macro.

Will send v2.

Kai-Heng

> 
> -- 
> https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 05c430b3489c..bc9982e77524 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -2,6 +2,8 @@ 
 /* Copyright(c) 2018-2019  Realtek Corporation
  */
 
+#include <linux/iopoll.h>
+
 #include "main.h"
 #include "coex.h"
 #include "fw.h"
@@ -193,8 +195,8 @@  static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 	u8 box;
 	u8 box_state;
 	u32 box_reg, box_ex_reg;
-	u32 h2c_wait;
 	int idx;
+	int ret;
 
 	rtw_dbg(rtwdev, RTW_DBG_FW,
 		"send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n",
@@ -226,12 +228,10 @@  static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 		goto out;
 	}
 
-	h2c_wait = 20;
-	do {
-		box_state = rtw_read8(rtwdev, REG_HMETFR);
-	} while ((box_state >> box) & 0x1 && --h2c_wait > 0);
+	ret = readx_poll_timeout(rr8, REG_HMETFR, box_state,
+				 !((box_state >> box) & 0x1), 100, 3000);
 
-	if (!h2c_wait) {
+	if (ret) {
 		rtw_err(rtwdev, "failed to send h2c command\n");
 		goto out;
 	}
diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 2cba327e6218..24062c7079c6 100644
--- a/drivers/net/wireless/realtek/rtw88/hci.h
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -253,6 +253,10 @@  rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u8 data)
 	rtw_write8(rtwdev, addr, set);
 }
 
+#define rr8(addr)      rtw_read8(rtwdev, addr)
+#define rr16(addr)     rtw_read16(rtwdev, addr)
+#define rr32(addr)     rtw_read32(rtwdev, addr)
+
 static inline enum rtw_hci_type rtw_hci_type(struct rtw_dev *rtwdev)
 {
 	return rtwdev->hci.type;