Message ID | 20240603145535.1858856-1-marcin.slusarz@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Ping-Ke Shih |
Headers | show |
Series | wifi: rtw88/usb: stop rx work before potential power off | expand |
Marcin Ślusarz <marcin.slusarz@gmail.com> wrote: > From: Marcin Ślusarz <mslusarz@renau.com> > > Avoids WARN_ON(!local->started) in ieee80211_rx_list, after > the patch that disables power management of 8821CU. Please describe how/what you do in this patch. > > Signed-off-by: Marcin Ślusarz <mslusarz@renau.com> > --- > drivers/net/wireless/realtek/rtw88/hci.h | 12 +++++++ > drivers/net/wireless/realtek/rtw88/main.c | 7 +++- > drivers/net/wireless/realtek/rtw88/pci.c | 6 ++++ > drivers/net/wireless/realtek/rtw88/sdio.c | 6 ++++ > drivers/net/wireless/realtek/rtw88/usb.c | 40 +++++++++++++++-------- > drivers/net/wireless/realtek/rtw88/usb.h | 1 + > 6 files changed, 58 insertions(+), 14 deletions(-) > > diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h > index 830d7532f2a3..d1b38b34fdd0 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,16 @@ 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) > +{ For PCI/SDIO nop, I would like to give them NULL, so here can be if (rtwdev->hci.ops->start_rx) rtwdev->hci.ops->start_rx(rtwdev); > + rtwdev->hci.ops->start_rx(rtwdev); > +} > + > +static inline void rtw_hci_stop_rx(struct rtw_dev *rtwdev) > +{ > + 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; rtw_hci_start_rx(rtwdev) is only needed by this case, so if (rtwdev->always_power_on && test_bit(RTW_FLAG_POWERON, rtwdev->flags)) { rtw_hci_start_rx(rtwdev); return 0; } > > 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); > + > 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); > + Similarly here can be if (rtwdev->always_power_on) { rtw_hci_stop_rx(rtwdev); return; } > if (rtwdev->always_power_on) > return; > > diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c > index 7a093f3d5f74..0a3ec94f6ab2 100644 > --- a/drivers/net/wireless/realtek/rtw88/pci.c > +++ b/drivers/net/wireless/realtek/rtw88/pci.c > @@ -1590,6 +1590,10 @@ static void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev) > rtw_pci_io_unmapping(rtwdev, pdev); > } > > +static void rtw_pci_nop(struct rtw_dev *rtwdev) > +{ > +} > + > static struct rtw_hci_ops rtw_pci_ops = { > .tx_write = rtw_pci_tx_write, > .tx_kick_off = rtw_pci_tx_kick_off, > @@ -1600,6 +1604,8 @@ static struct rtw_hci_ops rtw_pci_ops = { > .deep_ps = rtw_pci_deep_ps, > .link_ps = rtw_pci_link_ps, > .interface_cfg = rtw_pci_interface_cfg, > + .stop_rx = rtw_pci_nop, > + .start_rx = rtw_pci_nop, > > .read8 = rtw_pci_read8, > .read16 = rtw_pci_read16, > diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c > index 0cae5746f540..4a7923851c81 100644 > --- a/drivers/net/wireless/realtek/rtw88/sdio.c > +++ b/drivers/net/wireless/realtek/rtw88/sdio.c > @@ -1147,6 +1147,10 @@ static void rtw_sdio_declaim(struct rtw_dev *rtwdev, > sdio_release_host(sdio_func); > } > > +static void rtw_sdio_nop(struct rtw_dev *rtwdev) > +{ > +} > + > static struct rtw_hci_ops rtw_sdio_ops = { > .tx_write = rtw_sdio_tx_write, > .tx_kick_off = rtw_sdio_tx_kick_off, > @@ -1156,6 +1160,8 @@ static struct rtw_hci_ops rtw_sdio_ops = { > .deep_ps = rtw_sdio_deep_ps, > .link_ps = rtw_sdio_link_ps, > .interface_cfg = rtw_sdio_interface_cfg, > + .stop_rx = rtw_sdio_nop, > + .start_rx = rtw_sdio_nop, > > .read8 = rtw_sdio_read8, > .read16 = rtw_sdio_read16, > diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c > index e1b66f339cca..d5cf3eb51c8a 100644 > --- a/drivers/net/wireless/realtek/rtw88/usb.c > +++ b/drivers/net/wireless/realtek/rtw88/usb.c > @@ -716,6 +716,30 @@ 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); Do we really need a ' rtwusb->rx_enabled' to maintain symmetric calling of start/stop_rx? If yes, here should add if (!rtwusb->rx_enabled) return; But, I don't like that flag if it isn't strongly required. > + 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, > @@ -725,6 +749,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, > > .write8 = rtw_usb_write8, > .write16 = rtw_usb_write16, > @@ -754,18 +780,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); > @@ -903,7 +917,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 >
wt., 4 cze 2024 o 02:57 Ping-Ke Shih <pkshih@realtek.com> napisał(a): > > Marcin Ślusarz <marcin.slusarz@gmail.com> wrote: > > From: Marcin Ślusarz <mslusarz@renau.com> > > > > Avoids WARN_ON(!local->started) in ieee80211_rx_list, after > > the patch that disables power management of 8821CU. > > Please describe how/what you do in this patch. > > > > > Signed-off-by: Marcin Ślusarz <mslusarz@renau.com> > > --- > > drivers/net/wireless/realtek/rtw88/hci.h | 12 +++++++ > > drivers/net/wireless/realtek/rtw88/main.c | 7 +++- > > drivers/net/wireless/realtek/rtw88/pci.c | 6 ++++ > > drivers/net/wireless/realtek/rtw88/sdio.c | 6 ++++ > > drivers/net/wireless/realtek/rtw88/usb.c | 40 +++++++++++++++-------- > > drivers/net/wireless/realtek/rtw88/usb.h | 1 + > > 6 files changed, 58 insertions(+), 14 deletions(-) > > > > diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h > > index 830d7532f2a3..d1b38b34fdd0 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,16 @@ 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) > > +{ > > For PCI/SDIO nop, I would like to give them NULL, so here can be > > if (rtwdev->hci.ops->start_rx) > rtwdev->hci.ops->start_rx(rtwdev); Sure > > > + rtwdev->hci.ops->start_rx(rtwdev); > > +} > > + > > +static inline void rtw_hci_stop_rx(struct rtw_dev *rtwdev) > > +{ > > + 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; > > rtw_hci_start_rx(rtwdev) is only needed by this case, so > > if (rtwdev->always_power_on && test_bit(RTW_FLAG_POWERON, rtwdev->flags)) { > rtw_hci_start_rx(rtwdev); > return 0; > } Yes, strictly speaking, it's needed only in the always_power_on case, but doing that in the common code path ensures that it's tested and still works. > > > > > 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); > > + > > 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); > > + > > Similarly here can be > > if (rtwdev->always_power_on) { > rtw_hci_stop_rx(rtwdev); > return; > } Ditto > > > > if (rtwdev->always_power_on) > > return; > > > > diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c > > index 7a093f3d5f74..0a3ec94f6ab2 100644 > > --- a/drivers/net/wireless/realtek/rtw88/pci.c > > +++ b/drivers/net/wireless/realtek/rtw88/pci.c > > @@ -1590,6 +1590,10 @@ static void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev) > > rtw_pci_io_unmapping(rtwdev, pdev); > > } > > > > +static void rtw_pci_nop(struct rtw_dev *rtwdev) > > +{ > > +} > > + > > static struct rtw_hci_ops rtw_pci_ops = { > > .tx_write = rtw_pci_tx_write, > > .tx_kick_off = rtw_pci_tx_kick_off, > > @@ -1600,6 +1604,8 @@ static struct rtw_hci_ops rtw_pci_ops = { > > .deep_ps = rtw_pci_deep_ps, > > .link_ps = rtw_pci_link_ps, > > .interface_cfg = rtw_pci_interface_cfg, > > + .stop_rx = rtw_pci_nop, > > + .start_rx = rtw_pci_nop, > > > > .read8 = rtw_pci_read8, > > .read16 = rtw_pci_read16, > > diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c > > index 0cae5746f540..4a7923851c81 100644 > > --- a/drivers/net/wireless/realtek/rtw88/sdio.c > > +++ b/drivers/net/wireless/realtek/rtw88/sdio.c > > @@ -1147,6 +1147,10 @@ static void rtw_sdio_declaim(struct rtw_dev *rtwdev, > > sdio_release_host(sdio_func); > > } > > > > +static void rtw_sdio_nop(struct rtw_dev *rtwdev) > > +{ > > +} > > + > > static struct rtw_hci_ops rtw_sdio_ops = { > > .tx_write = rtw_sdio_tx_write, > > .tx_kick_off = rtw_sdio_tx_kick_off, > > @@ -1156,6 +1160,8 @@ static struct rtw_hci_ops rtw_sdio_ops = { > > .deep_ps = rtw_sdio_deep_ps, > > .link_ps = rtw_sdio_link_ps, > > .interface_cfg = rtw_sdio_interface_cfg, > > + .stop_rx = rtw_sdio_nop, > > + .start_rx = rtw_sdio_nop, > > > > .read8 = rtw_sdio_read8, > > .read16 = rtw_sdio_read16, > > diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c > > index e1b66f339cca..d5cf3eb51c8a 100644 > > --- a/drivers/net/wireless/realtek/rtw88/usb.c > > +++ b/drivers/net/wireless/realtek/rtw88/usb.c > > @@ -716,6 +716,30 @@ 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); > > Do we really need a ' rtwusb->rx_enabled' to maintain symmetric calling of > start/stop_rx? If yes, here should add > > if (!rtwusb->rx_enabled) > return; Sure > But, I don't like that flag if it isn't strongly required. It's required because start_rx is called twice initially - from rtw_usb_probe and rtw_core_start (via rtw_power_on). > > > + 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, > > @@ -725,6 +749,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, > > > > .write8 = rtw_usb_write8, > > .write16 = rtw_usb_write16, > > @@ -754,18 +780,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); > > @@ -903,7 +917,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 > > >
Marcin Ślusarz <marcin.slusarz@gmail.com> wrote: > wt., 4 cze 2024 o 02:57 Ping-Ke Shih <pkshih@realtek.com> napisał(a): > > > > Marcin Ślusarz <marcin.slusarz@gmail.com> wrote: > > > --- 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; > > > > rtw_hci_start_rx(rtwdev) is only needed by this case, so > > > > if (rtwdev->always_power_on && test_bit(RTW_FLAG_POWERON, rtwdev->flags)) { > > rtw_hci_start_rx(rtwdev); > > return 0; > > } > > Yes, strictly speaking, it's needed only in the always_power_on case, > but doing that in the common code path ensures that it's tested and > still works. For the non- always_power_on case, it calls rtw_hci_start()/rtw_hci_stop() already so I don't think we should call these duplicates.
diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h index 830d7532f2a3..d1b38b34fdd0 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,16 @@ 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) +{ + rtwdev->hci.ops->start_rx(rtwdev); +} + +static inline void rtw_hci_stop_rx(struct rtw_dev *rtwdev) +{ + 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); + 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); + if (rtwdev->always_power_on) return; diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 7a093f3d5f74..0a3ec94f6ab2 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1590,6 +1590,10 @@ static void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev) rtw_pci_io_unmapping(rtwdev, pdev); } +static void rtw_pci_nop(struct rtw_dev *rtwdev) +{ +} + static struct rtw_hci_ops rtw_pci_ops = { .tx_write = rtw_pci_tx_write, .tx_kick_off = rtw_pci_tx_kick_off, @@ -1600,6 +1604,8 @@ static struct rtw_hci_ops rtw_pci_ops = { .deep_ps = rtw_pci_deep_ps, .link_ps = rtw_pci_link_ps, .interface_cfg = rtw_pci_interface_cfg, + .stop_rx = rtw_pci_nop, + .start_rx = rtw_pci_nop, .read8 = rtw_pci_read8, .read16 = rtw_pci_read16, diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 0cae5746f540..4a7923851c81 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -1147,6 +1147,10 @@ static void rtw_sdio_declaim(struct rtw_dev *rtwdev, sdio_release_host(sdio_func); } +static void rtw_sdio_nop(struct rtw_dev *rtwdev) +{ +} + static struct rtw_hci_ops rtw_sdio_ops = { .tx_write = rtw_sdio_tx_write, .tx_kick_off = rtw_sdio_tx_kick_off, @@ -1156,6 +1160,8 @@ static struct rtw_hci_ops rtw_sdio_ops = { .deep_ps = rtw_sdio_deep_ps, .link_ps = rtw_sdio_link_ps, .interface_cfg = rtw_sdio_interface_cfg, + .stop_rx = rtw_sdio_nop, + .start_rx = rtw_sdio_nop, .read8 = rtw_sdio_read8, .read16 = rtw_sdio_read16, diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index e1b66f339cca..d5cf3eb51c8a 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -716,6 +716,30 @@ 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); + 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, @@ -725,6 +749,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, .write8 = rtw_usb_write8, .write16 = rtw_usb_write16, @@ -754,18 +780,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); @@ -903,7 +917,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)