mbox series

[v4,0/8] rtw88: improve TX performance in field

Message ID 20210115092405.8081-1-pkshih@realtek.com
Headers show
Series rtw88: improve TX performance in field | expand

Message

Ping-Ke Shih Jan. 15, 2021, 9:23 a.m. UTC
Improve TX performance in aspects of protocol and software design. Also,
update PHY parameters to fix incorrect RSSI report.

v2: Since 5/5 of v1 is too large, I split it into three patches.
v3: Since 6/7 of v2 is still too large for patchwork, I split parameter
    into four patches.
v4: tx work use work queue instead of bare kthread

Po-Hao Huang (8):
  rtw88: add dynamic rrsr configuration
  rtw88: add rts condition
  rtw88: add napi support
  rtw88: replace tx tasklet with work queue
  rtw88: 8822c: update MAC/BB parameter tables to v60
  rtw88: 8822c: update RF_A parameter tables to v60
  rtw88: 8822c: update RF_B (1/2) parameter tables to v60
  rtw88: 8822c: update RF_B (2/2) parameter tables to v60

 drivers/net/wireless/realtek/rtw88/mac80211.c |     2 +-
 drivers/net/wireless/realtek/rtw88/main.c     |     8 +-
 drivers/net/wireless/realtek/rtw88/main.h     |    10 +-
 drivers/net/wireless/realtek/rtw88/pci.c      |   108 +-
 drivers/net/wireless/realtek/rtw88/pci.h      |     5 +
 drivers/net/wireless/realtek/rtw88/phy.c      |    62 +-
 drivers/net/wireless/realtek/rtw88/phy.h      |     3 +
 drivers/net/wireless/realtek/rtw88/reg.h      |     2 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |     2 -
 .../wireless/realtek/rtw88/rtw8822c_table.c   | 32755 ++++++++++++----
 drivers/net/wireless/realtek/rtw88/tx.c       |    11 +-
 drivers/net/wireless/realtek/rtw88/tx.h       |     6 +-
 12 files changed, 24593 insertions(+), 8381 deletions(-)

Comments

Brian Norris Jan. 22, 2021, 10:57 p.m. UTC | #1
On Fri, Jan 15, 2021 at 1:26 AM Ping-Ke Shih <pkshih@realtek.com> wrote:
> --- a/drivers/net/wireless/realtek/rtw88/pci.c

> +++ b/drivers/net/wireless/realtek/rtw88/pci.c

> @@ -935,16 +935,49 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

>         ring->r.rp = cur_rp;

>  }

>

> -static void rtw_pci_rx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> +static void rtw_pci_rx_isr(struct rtw_dev *rtwdev)

> +{

> +       struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;

> +       struct napi_struct *napi = &rtwpci->napi;

> +

> +       napi_schedule(napi);


I don't claim to be all that familiar with NAPI, but my understanding
is that you are scheduling a NAPI poll, but immediately after you
return here, you're re-enabling your RX interrupt. That doesn't sound
like how NAPI is supposed to work -- you're supposed to wait to
re-enable your interrupt until you're done with your polling function.
Ref: https://wiki.linuxfoundation.org/networking/napi

> +}

...
> +static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

>                            u8 hw_queue)

...

Are you sure you don't want any locking in rtw_pci_rx_napi()?
Previously, you held irq_lock for the entirety of rtw_pci_rx_isr(),
but now all the RX work is being deferred to a NAPI context, without
any additional lock. IIUC, that means you can be both handling RX and
other ISR operations at the same time. Is that intentional?

> +static int rtw_pci_napi_poll(struct napi_struct *napi, int budget)

> +{

> +       struct rtw_pci *rtwpci = container_of(napi, struct rtw_pci, napi);

> +       struct rtw_dev *rtwdev = container_of((void *)rtwpci, struct rtw_dev,

> +                                             priv);

> +       int work_done = 0;

> +

> +       while (work_done < budget) {

> +               u32 work_done_once;

> +

> +               work_done_once = rtw_pci_rx_napi(rtwdev, rtwpci,

> +                                                RTW_RX_QUEUE_MPDU);

> +               if (work_done_once == 0)

> +                       break;

> +               work_done += work_done_once;

> +       }

> +       if (work_done < budget) {

> +               napi_complete_done(napi, work_done);

> +               /* When ISR happens during polling and before napi_complete

> +                * while no further data is received. Data on the dma_ring will

> +                * not be processed immediately. Check whether dma ring is

> +                * empty and perform napi_schedule accordingly.

> +                */

> +               if (rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci, NULL, NULL))

> +                       napi_schedule(napi);

> +       }

> +

> +       return work_done;

> +}

> +

> +static void rtw_pci_napi_init(struct rtw_dev *rtwdev)

> +{

> +       struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;

> +

> +       init_dummy_netdev(&rtwpci->netdev);

> +       netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll,

> +                      RTW_NAPI_WEIGHT_NUM);

> +       napi_enable(&rtwpci->napi);

> +}

...
> @@ -1547,6 +1624,8 @@ int rtw_pci_probe(struct pci_dev *pdev,

>                 goto err_destroy_pci;

>         }

>

> +       rtw_pci_napi_init(rtwdev);


You're initializing NAPI after you've already established your ISR,
and your ISR might start scheduling NAPI. Even if that's unlikely
(because you haven't initiated any RX traffic yet), it seems like an
ordering problem -- shouldn't you initialize the NAPI device, then set
up the ISR, and only then call napi_enable()?

Brian

> +

>         return 0;

>

>  err_destroy_pci:
Ping-Ke Shih Jan. 28, 2021, 9:45 a.m. UTC | #2
> -----Original Message-----

> From: Brian Norris [mailto:briannorris@chromium.org]

> Sent: Saturday, January 23, 2021 6:58 AM

> To: Pkshih

> Cc: Yan-Hsuan Chuang; Kalle Valo; linux-wireless; Bernie Huang

> Subject: Re: [PATCH v4 3/8] rtw88: add napi support

> 

> On Fri, Jan 15, 2021 at 1:26 AM Ping-Ke Shih <pkshih@realtek.com> wrote:

> > --- a/drivers/net/wireless/realtek/rtw88/pci.c

> > +++ b/drivers/net/wireless/realtek/rtw88/pci.c

> > @@ -935,16 +935,49 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> >         ring->r.rp = cur_rp;

> >  }

> >

> > -static void rtw_pci_rx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> > +static void rtw_pci_rx_isr(struct rtw_dev *rtwdev)

> > +{

> > +       struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;

> > +       struct napi_struct *napi = &rtwpci->napi;

> > +

> > +       napi_schedule(napi);

> 

> I don't claim to be all that familiar with NAPI, but my understanding

> is that you are scheduling a NAPI poll, but immediately after you

> return here, you're re-enabling your RX interrupt. That doesn't sound

> like how NAPI is supposed to work -- you're supposed to wait to

> re-enable your interrupt until you're done with your polling function.

> Ref: https://wiki.linuxfoundation.org/networking/napi

> 


Will re-enable RX IMR until napi_poll function is done.

> > +}

> ...

> > +static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> >                            u8 hw_queue)

> ...

> 

> Are you sure you don't want any locking in rtw_pci_rx_napi()?

> Previously, you held irq_lock for the entirety of rtw_pci_rx_isr(),

> but now all the RX work is being deferred to a NAPI context, without

> any additional lock. IIUC, that means you can be both handling RX and

> other ISR operations at the same time. Is that intentional?

> 


irq_lock is used to protect TX ring->queue. The TX skb(s) are queued into the
queue, and unlink the skb until TX_OK_ISR is received. So, RX doesn't need to
hold this lock.

> > +static int rtw_pci_napi_poll(struct napi_struct *napi, int budget)

> > +{

> > +       struct rtw_pci *rtwpci = container_of(napi, struct rtw_pci, napi);

> > +       struct rtw_dev *rtwdev = container_of((void *)rtwpci, struct rtw_dev,

> > +                                             priv);

> > +       int work_done = 0;

> > +

> > +       while (work_done < budget) {

> > +               u32 work_done_once;

> > +

> > +               work_done_once = rtw_pci_rx_napi(rtwdev, rtwpci,

> > +                                                RTW_RX_QUEUE_MPDU);

> > +               if (work_done_once == 0)

> > +                       break;

> > +               work_done += work_done_once;

> > +       }

> > +       if (work_done < budget) {

> > +               napi_complete_done(napi, work_done);

> > +               /* When ISR happens during polling and before napi_complete

> > +                * while no further data is received. Data on the dma_ring will

> > +                * not be processed immediately. Check whether dma ring is

> > +                * empty and perform napi_schedule accordingly.

> > +                */

> > +               if (rtw_pci_get_hw_rx_ring_nr(rtwdev, rtwpci, NULL, NULL))

> > +                       napi_schedule(napi);

> > +       }

> > +

> > +       return work_done;

> > +}

> > +

> > +static void rtw_pci_napi_init(struct rtw_dev *rtwdev)

> > +{

> > +       struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;

> > +

> > +       init_dummy_netdev(&rtwpci->netdev);

> > +       netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll,

> > +                      RTW_NAPI_WEIGHT_NUM);

> > +       napi_enable(&rtwpci->napi);

> > +}

> ...

> > @@ -1547,6 +1624,8 @@ int rtw_pci_probe(struct pci_dev *pdev,

> >                 goto err_destroy_pci;

> >         }

> >

> > +       rtw_pci_napi_init(rtwdev);

> 

> You're initializing NAPI after you've already established your ISR,

> and your ISR might start scheduling NAPI. Even if that's unlikely

> (because you haven't initiated any RX traffic yet), it seems like an

> ordering problem -- shouldn't you initialize the NAPI device, then set

> up the ISR, and only then call napi_enable()?

> 


Will do it.

Thanks for your advice.

---
Ping-Ke
Brian Norris Jan. 29, 2021, 11:39 p.m. UTC | #3
On Thu, Jan 28, 2021 at 1:45 AM Pkshih <pkshih@realtek.com> wrote:
> > -----Original Message-----

> > From: Brian Norris [mailto:briannorris@chromium.org]

> > On Fri, Jan 15, 2021 at 1:26 AM Ping-Ke Shih <pkshih@realtek.com> wrote:

> > > +static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> > >                            u8 hw_queue)

> > ...

> >

> > Are you sure you don't want any locking in rtw_pci_rx_napi()?

> > Previously, you held irq_lock for the entirety of rtw_pci_rx_isr(),

> > but now all the RX work is being deferred to a NAPI context, without

> > any additional lock. IIUC, that means you can be both handling RX and

> > other ISR operations at the same time. Is that intentional?

> >

>

> irq_lock is used to protect TX ring->queue. The TX skb(s) are queued into the

> queue, and unlink the skb until TX_OK_ISR is received. So, RX doesn't need to

> hold this lock.


I could be misunderstanding your locking model, but IIUC, you're left
with zero locking between NAPI RX and all other operations (H2C, link
up/down -- including DMA free, etc.). irq_lock used to protect you
from that.

If I'm right, maybe it needs a rename and/or some additional comments.

Brian
Ping-Ke Shih Feb. 1, 2021, 6:38 a.m. UTC | #4
> -----Original Message-----

> From: Brian Norris [mailto:briannorris@chromium.org]

> Sent: Saturday, January 30, 2021 7:39 AM

> To: Pkshih

> Cc: Yan-Hsuan Chuang; Kalle Valo; linux-wireless; Bernie Huang

> Subject: Re: [PATCH v4 3/8] rtw88: add napi support

> 

> On Thu, Jan 28, 2021 at 1:45 AM Pkshih <pkshih@realtek.com> wrote:

> > > -----Original Message-----

> > > From: Brian Norris [mailto:briannorris@chromium.org]

> > > On Fri, Jan 15, 2021 at 1:26 AM Ping-Ke Shih <pkshih@realtek.com> wrote:

> > > > +static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,

> > > >                            u8 hw_queue)

> > > ...

> > >

> > > Are you sure you don't want any locking in rtw_pci_rx_napi()?

> > > Previously, you held irq_lock for the entirety of rtw_pci_rx_isr(),

> > > but now all the RX work is being deferred to a NAPI context, without

> > > any additional lock. IIUC, that means you can be both handling RX and

> > > other ISR operations at the same time. Is that intentional?

> > >

> >

> > irq_lock is used to protect TX ring->queue. The TX skb(s) are queued into the

> > queue, and unlink the skb until TX_OK_ISR is received. So, RX doesn't need to

> > hold this lock.

> 

> I could be misunderstanding your locking model, but IIUC, you're left

> with zero locking between NAPI RX and all other operations (H2C, link

> up/down -- including DMA free, etc.). irq_lock used to protect you

> from that.

> 


Sorry, I'm wrong. I think irq_lock is used to protect not only TX ring->queue
but also TX/RX rings. The RX ring rtwpci->rx_rings[RTW_RX_QUEUE_MPDU] is reset
by rtw_pci_reset_buf_desc() when pci_stop(), and napi_poll() also uses it to
know how many RX packets are needed to be received. Therefore, we plan to
use irq_lock to protect napi_poll(), and then see if it affects performance.

> If I'm right, maybe it needs a rename and/or some additional comments.

> 


The original name and comment:
	/* Used for PCI TX queueing. */
	spinlock_t irq_lock;
Will change to
	/* Used for PCI TX/RX rings and TX queueing. */
	spinlock_t irq_lock;

---
Ping-Ke
Ping-Ke Shih Feb. 9, 2021, 7:19 a.m. UTC | #5
On Mon, 2021-02-01 at 06:38 +0000, Pkshih wrote:
> > -----Original Message-----

> > From: Brian Norris [mailto:briannorris@chromium.org]

> > Sent: Saturday, January 30, 2021 7:39 AM

> > To: Pkshih

> > Cc: Yan-Hsuan Chuang; Kalle Valo; linux-wireless; Bernie Huang

> > Subject: Re: [PATCH v4 3/8] rtw88: add napi support

> > 

> > On Thu, Jan 28, 2021 at 1:45 AM Pkshih <pkshih@realtek.com> wrote:

> > > > -----Original Message-----

> > > > From: Brian Norris [mailto:briannorris@chromium.org]

> > > > On Fri, Jan 15, 2021 at 1:26 AM Ping-Ke Shih <pkshih@realtek.com> wrote:

> > > > > +static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci

> *rtwpci,

> > > > >                            u8 hw_queue)

> > > > ...

> > > >

> > > > Are you sure you don't want any locking in rtw_pci_rx_napi()?

> > > > Previously, you held irq_lock for the entirety of rtw_pci_rx_isr(),

> > > > but now all the RX work is being deferred to a NAPI context, without

> > > > any additional lock. IIUC, that means you can be both handling RX and

> > > > other ISR operations at the same time. Is that intentional?

> > > >

> > >

> > > irq_lock is used to protect TX ring->queue. The TX skb(s) are queued into

> the

> > > queue, and unlink the skb until TX_OK_ISR is received. So, RX doesn't need

> to

> > > hold this lock.

> > 

> > I could be misunderstanding your locking model, but IIUC, you're left

> > with zero locking between NAPI RX and all other operations (H2C, link

> > up/down -- including DMA free, etc.). irq_lock used to protect you

> > from that.

> > 

> 

> Sorry, I'm wrong. I think irq_lock is used to protect not only TX ring->queue

> but also TX/RX rings. The RX ring rtwpci->rx_rings[RTW_RX_QUEUE_MPDU] is reset

> by rtw_pci_reset_buf_desc() when pci_stop(), and napi_poll() also uses it to

> know how many RX packets are needed to be received. Therefore, we plan to

> use irq_lock to protect napi_poll(), and then see if it affects performance.

> 


I change my mind, because using irq_lock to protect napi_poll causes deadlock.
I think that it's disallowed to hold a spin_lock_bh and call napi APIs that uses
RCU lock.

Then, I have another simple thinking -- enable NAPI only if interrupt is
enabled. Other operations with RX ring are working only if interrupt is
disabled. So, we don't need a lock to protect RX ring at all.

The irq_lock is still used to protect TX ring/queue, and now it also used
to protect switching IMR. Some comments are added to describe about this.

Above is implemented in v5.

---
Ping-Ke
Brian Norris Feb. 11, 2021, 8:30 p.m. UTC | #6
On Mon, Feb 8, 2021 at 11:19 PM Pkshih <pkshih@realtek.com> wrote:
> Then, I have another simple thinking -- enable NAPI only if interrupt is

> enabled. Other operations with RX ring are working only if interrupt is

> disabled. So, we don't need a lock to protect RX ring at all.


That makes more sense; thanks for the update.

> The irq_lock is still used to protect TX ring/queue, and now it also used

> to protect switching IMR. Some comments are added to describe about this.

>

> Above is implemented in v5.


I've taken a brief look, and that looks better. I'll likely provide my
Reviewed-by there.

Thanks,
Brian