Search Linux Wireless

RE: [PATCH v2 2/2] wifi: rtw88/usb: stop rx work before potential power off

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

 



Marcin Ślusarz <marcin.slusarz@xxxxxxxxx> wrote:
> If power off is disabled (like on 8821CU after previous patch),
> the hardware can still fire and deliver data. This may have
> undersired impact on the networking stack (e.g.
> WARN_ON(!local->started) in ieee80211_rx_list), because hw is
> not supposed to do that after power off.
> 
> So to prevent that, cancel any pending RX URBs to stop the
> completion handlers from being called.
> 
> Signed-off-by: Marcin Ślusarz <mslusarz@xxxxxxxxx>
> ---
> v2: start_rx/stop_rx cbs can be NULL; rx_enabled check added to stop_rx
> ---
>  drivers/net/wireless/realtek/rtw88/hci.h  | 14 ++++++++
>  drivers/net/wireless/realtek/rtw88/main.c |  7 +++-
>  drivers/net/wireless/realtek/rtw88/usb.c  | 44 ++++++++++++++++-------
>  drivers/net/wireless/realtek/rtw88/usb.h  |  1 +
>  4 files changed, 52 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
> index 830d7532f2a3..839b9161014f 100644
> --- a/drivers/net/wireless/realtek/rtw88/hci.h
> +++ b/drivers/net/wireless/realtek/rtw88/hci.h
> @@ -18,6 +18,8 @@ struct rtw_hci_ops {
>         void (*deep_ps)(struct rtw_dev *rtwdev, bool enter);
>         void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
>         void (*interface_cfg)(struct rtw_dev *rtwdev);
> +       void (*stop_rx)(struct rtw_dev *rtwdev);
> +       void (*start_rx)(struct rtw_dev *rtwdev);
> 
>         int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
>         int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
> @@ -57,6 +59,18 @@ static inline void rtw_hci_stop(struct rtw_dev *rtwdev)
>         rtwdev->hci.ops->stop(rtwdev);
>  }
> 
> +static inline void rtw_hci_start_rx(struct rtw_dev *rtwdev)
> +{
> +       if (rtwdev->hci.ops->start_rx)
> +               rtwdev->hci.ops->start_rx(rtwdev);
> +}
> +
> +static inline void rtw_hci_stop_rx(struct rtw_dev *rtwdev)
> +{
> +       if (rtwdev->hci.ops->stop_rx)
> +               rtwdev->hci.ops->stop_rx(rtwdev);
> +}
> +
>  static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter)
>  {
>         rtwdev->hci.ops->deep_ps(rtwdev, enter);
> diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
> index a48e919adddb..bb0122d19416 100644
> --- a/drivers/net/wireless/realtek/rtw88/main.c
> +++ b/drivers/net/wireless/realtek/rtw88/main.c
> @@ -1357,7 +1357,7 @@ static int rtw_power_on(struct rtw_dev *rtwdev)
>         int ret;
> 
>         if (rtwdev->always_power_on && test_bit(RTW_FLAG_POWERON, rtwdev->flags))
> -               return 0;
> +               goto success;
> 
>         ret = rtw_hci_setup(rtwdev);
>         if (ret) {
> @@ -1407,6 +1407,9 @@ static int rtw_power_on(struct rtw_dev *rtwdev)
>         rtw_coex_power_on_setting(rtwdev);
>         rtw_coex_init_hw_config(rtwdev, wifi_only);
> 
> +success:
> +       rtw_hci_start_rx(rtwdev);
> +

As mentioned, this is not a common routine, but only special for always_power_on case.
For normal case, running both rtw_hci_start() and rtw_hci_start_rx() are
confusing. Even I'm thinking the names of these two ops are confusing people. 

>         return 0;
> 
>  err_off:
> @@ -1509,6 +1512,8 @@ int rtw_core_start(struct rtw_dev *rtwdev)
> 
>  static void rtw_power_off(struct rtw_dev *rtwdev)
>  {
> +       rtw_hci_stop_rx(rtwdev);
> +

Ditto. 

>         if (rtwdev->always_power_on)
>                 return;
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
> index 28ff46e96604..8e784c357ee2 100644
> --- a/drivers/net/wireless/realtek/rtw88/usb.c
> +++ b/drivers/net/wireless/realtek/rtw88/usb.c
> @@ -713,6 +713,34 @@ static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev)
>         /* empty function for rtw_hci_ops */
>  }
> 
> +static void rtw_usb_stop_rx(struct rtw_dev *rtwdev)
> +{
> +       struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
> +
> +       if (!rtwusb->rx_enabled)
> +               return;
> +
> +       rtw_usb_cancel_rx_bufs(rtwusb);
> +       rtwusb->rx_enabled = false;
> +}
> +
> +static void rtw_usb_start_rx(struct rtw_dev *rtwdev)
> +{
> +       struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
> +       int i;
> +
> +       if (rtwusb->rx_enabled)
> +               return;
> +
> +       for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
> +               struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
> +
> +               rtw_usb_rx_resubmit(rtwusb, rxcb);
> +       }
> +
> +       rtwusb->rx_enabled = true;
> +}
> +
>  static struct rtw_hci_ops rtw_usb_ops = {
>         .tx_write = rtw_usb_tx_write,
>         .tx_kick_off = rtw_usb_tx_kick_off,
> @@ -722,6 +750,8 @@ static struct rtw_hci_ops rtw_usb_ops = {
>         .deep_ps = rtw_usb_deep_ps,
>         .link_ps = rtw_usb_link_ps,
>         .interface_cfg = rtw_usb_interface_cfg,
> +       .stop_rx = rtw_usb_stop_rx,
> +       .start_rx = rtw_usb_start_rx,

Please set .stop_rx/.start_rx to NULL for PCI and SDIO explicitly. 


> 
>         .write8  = rtw_usb_write8,
>         .write16 = rtw_usb_write16,
> @@ -751,18 +781,6 @@ static int rtw_usb_init_rx(struct rtw_dev *rtwdev)
>         return 0;
>  }
> 
> -static void rtw_usb_setup_rx(struct rtw_dev *rtwdev)
> -{
> -       struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
> -       int i;
> -
> -       for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
> -               struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
> -
> -               rtw_usb_rx_resubmit(rtwusb, rxcb);
> -       }
> -}
> -
>  static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev)
>  {
>         struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
> @@ -900,7 +918,7 @@ int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
>                 goto err_destroy_rxwq;
>         }
> 
> -       rtw_usb_setup_rx(rtwdev);
> +       rtw_usb_start_rx(rtwdev);
> 
>         return 0;
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h
> index 86697a5c0103..a6b004d4f74e 100644
> --- a/drivers/net/wireless/realtek/rtw88/usb.h
> +++ b/drivers/net/wireless/realtek/rtw88/usb.h
> @@ -82,6 +82,7 @@ struct rtw_usb {
>         struct rx_usb_ctrl_block rx_cb[RTW_USB_RXCB_NUM];
>         struct sk_buff_head rx_queue;
>         struct work_struct rx_work;
> +       bool rx_enabled;
>  };
> 
>  static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
> --
> 2.25.1
> 





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux