All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Arnd Bergmann <arnd@arndb.de>
Cc: Jonathan Corbet <corbet@lwn.net>,
	Rob Herring <robh+dt@kernel.org>,
	"David S . Miller" <davem@davemloft.net>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	John Crispin <john@phrozen.org>,
	Sean Wang <sean.wang@mediatek.com>,
	Mark Lee <Mark-MC.Lee@mediatek.com>,
	Jakub Kicinski <kuba@kernel.org>,
	Fabien Parent <fparent@baylibre.com>,
	Heiner Kallweit <hkallweit1@gmail.com>,
	Edwin Peer <edwin.peer@broadcom.com>,
	DTML <devicetree@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Networking <netdev@vger.kernel.org>,
	Linux ARM <linux-arm-kernel@lists.infradead.org>,
	"moderated list:ARM/Mediatek SoC..." 
	<linux-mediatek@lists.infradead.org>,
	Stephane Le Provost <stephane.leprovost@mediatek.com>,
	Pedro Tsai <pedro.tsai@mediatek.com>,
	Andrew Perepech <andrew.perepech@mediatek.com>,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>
Subject: Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
Date: Fri, 15 May 2020 09:11:14 +0200	[thread overview]
Message-ID: <CAMRc=MeypzZBHo6dJGKm4JujYyejqHxtdo7Ts95DXuL0VuMYCw@mail.gmail.com> (raw)
In-Reply-To: <CAK8P3a3=xgbvqrSpCK5h96eRH32AA7xnoK2ossvT0-cLFLzmXA@mail.gmail.com>

czw., 14 maj 2020 o 18:19 Arnd Bergmann <arnd@arndb.de> napisał(a):
>
> On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> > family. For now we only support full-duplex.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Looks very nice overall. Just a few things I noticed, and some ideas
> that may or may not make sense:
>
> > +/* This is defined to 0 on arm64 in arch/arm64/include/asm/processor.h but
> > + * this IP doesn't work without this alignment being equal to 2.
> > + */
> > +#ifdef NET_IP_ALIGN
> > +#undef NET_IP_ALIGN
> > +#endif
> > +#define NET_IP_ALIGN                           2
>
> Maybe you should just define your own macro instead of replacing
> the normal one then?
>

I did in an earlier version and was told to use NET_IP_ALIGN but then
found out its value on arm64 doesn't work for me so I did the thing
that won't make anybody happy - redefine the existing constant. :)

> > +static void mtk_mac_lock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_lock_irqsave(&priv->lock, priv->lock_flags);
> > +}
> > +
> > +static void mtk_mac_unlock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_unlock_irqrestore(&priv->lock, priv->lock_flags);
> > +}
>
> This looks wrong: you should not have shared 'flags' passed into
> spin_lock_irqsave(), and I don't even see a need to use the
> irqsave variant of the lock in the first place.
>
> Maybe start by open-coding the lock and remove the wrappers
> above.
>
> Then see if you can use a cheaper spin_lock_bh() or plain spin_lock()
> instead of irqsave.
>

This is from an earlier version where I did a lot more in hard irq
context. Now that almost all of the processing happens in soft-irq
context I guess you're right - I can go with a regular spin_lock().

> Finally, see if this can be done in a lockless way by relying on
> appropriate barriers and separating the writers into separate
> cache lines. From a brief look at the driver I think it can be done
> without too much trouble.
>

Unfortunately I do need some locking. Accessing RX and TX descriptors
at the same time seems to upset the controller. I experimented a lot
with barriers but it turned out that I got a lot of weird bugs at high
throughput.

> > +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> > +{
> > +       unsigned int val;
> > +
> > +       regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> > +       regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> > +
> > +       return val;
> > +}
>
> Do you actually need to read the register? That is usually a relatively
> expensive operation, so if possible try to use clear the bits when
> you don't care which bits were set.
>

I do care, I'm afraid. The returned value is being used in the napi
poll callback to see which ring to process.

> > +/* All processing for TX and RX happens in the napi poll callback. */
> > +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       struct net_device *ndev;
> > +
> > +       ndev = data;
> > +       priv = netdev_priv(ndev);
> > +
> > +       if (netif_running(ndev)) {
> > +               mtk_mac_intr_mask_all(priv);
> > +               napi_schedule(&priv->napi);
> > +       }
> > +
> > +       return IRQ_HANDLED;
>
>
> > +static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
> > +                                    struct net_device *ndev)
> > +{
> > +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct device *dev = mtk_mac_get_dev(priv);
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +
> > +       desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
> > +       if (dma_mapping_error(dev, desc_data.dma_addr))
> > +               goto err_drop_packet;
> > +
> > +       desc_data.skb = skb;
> > +       desc_data.len = skb->len;
> > +
> > +       mtk_mac_lock(priv);
> > +       mtk_mac_ring_push_head_tx(ring, &desc_data);
> > +
> > +       if (mtk_mac_ring_full(ring))
> > +               netif_stop_queue(ndev);
> > +       mtk_mac_unlock(priv);
> > +
> > +       mtk_mac_dma_resume_tx(priv);
> > +
> > +       return NETDEV_TX_OK;
> > +
> > +err_drop_packet:
> > +       dev_kfree_skb(skb);
> > +       ndev->stats.tx_dropped++;
> > +       return NETDEV_TX_BUSY;
> > +}
>
> I would always add BQL flow control in new drivers, using
> netdev_sent_queue here...
>

Ok, will do.

> > +static int mtk_mac_tx_complete_one(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +       int ret;
> > +
> > +       ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> > +       if (ret)
> > +               return ret;
> > +
> > +       mtk_mac_dma_unmap_tx(priv, &desc_data);
> > +       dev_kfree_skb_irq(desc_data.skb);
> > +
> > +       return 0;
> > +}
>
> ... and netdev_completed_queue()  here.
>

Same here.

> > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct net_device *ndev = priv->ndev;
> > +       int ret;
> > +
> > +       for (;;) {
> > +               mtk_mac_lock(priv);
> > +
> > +               if (!mtk_mac_ring_descs_available(ring)) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               ret = mtk_mac_tx_complete_one(priv);
> > +               if (ret) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               if (netif_queue_stopped(ndev))
> > +                       netif_wake_queue(ndev);
> > +
> > +               mtk_mac_unlock(priv);
> > +       }
> > +}
>
> It looks like most of the stuff inside of the loop can be pulled out
> and only done once here.
>

I did that in one of the previous submissions but it was pointed out
to me that a parallel TX path may fill up the queue before I wake it.

> > +static int mtk_mac_poll(struct napi_struct *napi, int budget)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       unsigned int status;
> > +       int received = 0;
> > +
> > +       priv = container_of(napi, struct mtk_mac_priv, napi);
> > +
> > +       status = mtk_mac_intr_read_and_clear(priv);
> > +
> > +       /* Clean up TX */
> > +       if (status & MTK_MAC_BIT_INT_STS_TNTC)
> > +               mtk_mac_tx_complete_all(priv);
> > +
> > +       /* Receive up to $budget packets */
> > +       if (status & MTK_MAC_BIT_INT_STS_FNRC)
> > +               received = mtk_mac_process_rx(priv, budget);
> > +
> > +       /* One of the counter reached 0x8000000 - update stats and reset all
> > +        * counters.
> > +        */
> > +       if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> > +               mtk_mac_update_stats(priv);
> > +               mtk_mac_reset_counters(priv);
> > +       }
> > +
> > +       if (received < budget)
> > +               napi_complete_done(napi, received);
> > +
> > +       mtk_mac_intr_unmask_all(priv);
> > +
> > +       return received;
> > +}
>
> I think you want to leave (at least some of) the interrupts masked
> if your budget is exhausted, to avoid generating unnecessary
> irqs.
>

The networking stack shouldn't queue any new TX packets if the queue
is stopped - is this really worth complicating the code? Looks like
premature optimization IMO.

> It may also be faster to not mask/unmask at all but just
> clear the interrupts that you have finished processing
>

Bart

WARNING: multiple messages have this Message-ID (diff)
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Arnd Bergmann <arnd@arndb.de>
Cc: Edwin Peer <edwin.peer@broadcom.com>,
	DTML <devicetree@vger.kernel.org>,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>,
	Stephane Le Provost <stephane.leprovost@mediatek.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Networking <netdev@vger.kernel.org>,
	Sean Wang <sean.wang@mediatek.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Pedro Tsai <pedro.tsai@mediatek.com>,
	Mark Lee <Mark-MC.Lee@mediatek.com>,
	Fabien Parent <fparent@baylibre.com>,
	Rob Herring <robh+dt@kernel.org>,
	"moderated list:ARM/Mediatek SoC..."
	<linux-mediatek@lists.infradead.org>,
	Andrew Perepech <andrew.perepech@mediatek.com>,
	John Crispin <john@phrozen.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Jakub Kicinski <kuba@kernel.org>,
	"David S . Miller" <davem@davemloft.net>,
	Linux ARM <linux-arm-kernel@lists.infradead.org>,
	Heiner Kallweit <hkallweit1@gmail.com>
Subject: Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
Date: Fri, 15 May 2020 09:11:14 +0200	[thread overview]
Message-ID: <CAMRc=MeypzZBHo6dJGKm4JujYyejqHxtdo7Ts95DXuL0VuMYCw@mail.gmail.com> (raw)
In-Reply-To: <CAK8P3a3=xgbvqrSpCK5h96eRH32AA7xnoK2ossvT0-cLFLzmXA@mail.gmail.com>

czw., 14 maj 2020 o 18:19 Arnd Bergmann <arnd@arndb.de> napisał(a):
>
> On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> > family. For now we only support full-duplex.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Looks very nice overall. Just a few things I noticed, and some ideas
> that may or may not make sense:
>
> > +/* This is defined to 0 on arm64 in arch/arm64/include/asm/processor.h but
> > + * this IP doesn't work without this alignment being equal to 2.
> > + */
> > +#ifdef NET_IP_ALIGN
> > +#undef NET_IP_ALIGN
> > +#endif
> > +#define NET_IP_ALIGN                           2
>
> Maybe you should just define your own macro instead of replacing
> the normal one then?
>

I did in an earlier version and was told to use NET_IP_ALIGN but then
found out its value on arm64 doesn't work for me so I did the thing
that won't make anybody happy - redefine the existing constant. :)

> > +static void mtk_mac_lock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_lock_irqsave(&priv->lock, priv->lock_flags);
> > +}
> > +
> > +static void mtk_mac_unlock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_unlock_irqrestore(&priv->lock, priv->lock_flags);
> > +}
>
> This looks wrong: you should not have shared 'flags' passed into
> spin_lock_irqsave(), and I don't even see a need to use the
> irqsave variant of the lock in the first place.
>
> Maybe start by open-coding the lock and remove the wrappers
> above.
>
> Then see if you can use a cheaper spin_lock_bh() or plain spin_lock()
> instead of irqsave.
>

This is from an earlier version where I did a lot more in hard irq
context. Now that almost all of the processing happens in soft-irq
context I guess you're right - I can go with a regular spin_lock().

> Finally, see if this can be done in a lockless way by relying on
> appropriate barriers and separating the writers into separate
> cache lines. From a brief look at the driver I think it can be done
> without too much trouble.
>

Unfortunately I do need some locking. Accessing RX and TX descriptors
at the same time seems to upset the controller. I experimented a lot
with barriers but it turned out that I got a lot of weird bugs at high
throughput.

> > +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> > +{
> > +       unsigned int val;
> > +
> > +       regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> > +       regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> > +
> > +       return val;
> > +}
>
> Do you actually need to read the register? That is usually a relatively
> expensive operation, so if possible try to use clear the bits when
> you don't care which bits were set.
>

I do care, I'm afraid. The returned value is being used in the napi
poll callback to see which ring to process.

> > +/* All processing for TX and RX happens in the napi poll callback. */
> > +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       struct net_device *ndev;
> > +
> > +       ndev = data;
> > +       priv = netdev_priv(ndev);
> > +
> > +       if (netif_running(ndev)) {
> > +               mtk_mac_intr_mask_all(priv);
> > +               napi_schedule(&priv->napi);
> > +       }
> > +
> > +       return IRQ_HANDLED;
>
>
> > +static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
> > +                                    struct net_device *ndev)
> > +{
> > +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct device *dev = mtk_mac_get_dev(priv);
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +
> > +       desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
> > +       if (dma_mapping_error(dev, desc_data.dma_addr))
> > +               goto err_drop_packet;
> > +
> > +       desc_data.skb = skb;
> > +       desc_data.len = skb->len;
> > +
> > +       mtk_mac_lock(priv);
> > +       mtk_mac_ring_push_head_tx(ring, &desc_data);
> > +
> > +       if (mtk_mac_ring_full(ring))
> > +               netif_stop_queue(ndev);
> > +       mtk_mac_unlock(priv);
> > +
> > +       mtk_mac_dma_resume_tx(priv);
> > +
> > +       return NETDEV_TX_OK;
> > +
> > +err_drop_packet:
> > +       dev_kfree_skb(skb);
> > +       ndev->stats.tx_dropped++;
> > +       return NETDEV_TX_BUSY;
> > +}
>
> I would always add BQL flow control in new drivers, using
> netdev_sent_queue here...
>

Ok, will do.

> > +static int mtk_mac_tx_complete_one(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +       int ret;
> > +
> > +       ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> > +       if (ret)
> > +               return ret;
> > +
> > +       mtk_mac_dma_unmap_tx(priv, &desc_data);
> > +       dev_kfree_skb_irq(desc_data.skb);
> > +
> > +       return 0;
> > +}
>
> ... and netdev_completed_queue()  here.
>

Same here.

> > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct net_device *ndev = priv->ndev;
> > +       int ret;
> > +
> > +       for (;;) {
> > +               mtk_mac_lock(priv);
> > +
> > +               if (!mtk_mac_ring_descs_available(ring)) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               ret = mtk_mac_tx_complete_one(priv);
> > +               if (ret) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               if (netif_queue_stopped(ndev))
> > +                       netif_wake_queue(ndev);
> > +
> > +               mtk_mac_unlock(priv);
> > +       }
> > +}
>
> It looks like most of the stuff inside of the loop can be pulled out
> and only done once here.
>

I did that in one of the previous submissions but it was pointed out
to me that a parallel TX path may fill up the queue before I wake it.

> > +static int mtk_mac_poll(struct napi_struct *napi, int budget)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       unsigned int status;
> > +       int received = 0;
> > +
> > +       priv = container_of(napi, struct mtk_mac_priv, napi);
> > +
> > +       status = mtk_mac_intr_read_and_clear(priv);
> > +
> > +       /* Clean up TX */
> > +       if (status & MTK_MAC_BIT_INT_STS_TNTC)
> > +               mtk_mac_tx_complete_all(priv);
> > +
> > +       /* Receive up to $budget packets */
> > +       if (status & MTK_MAC_BIT_INT_STS_FNRC)
> > +               received = mtk_mac_process_rx(priv, budget);
> > +
> > +       /* One of the counter reached 0x8000000 - update stats and reset all
> > +        * counters.
> > +        */
> > +       if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> > +               mtk_mac_update_stats(priv);
> > +               mtk_mac_reset_counters(priv);
> > +       }
> > +
> > +       if (received < budget)
> > +               napi_complete_done(napi, received);
> > +
> > +       mtk_mac_intr_unmask_all(priv);
> > +
> > +       return received;
> > +}
>
> I think you want to leave (at least some of) the interrupts masked
> if your budget is exhausted, to avoid generating unnecessary
> irqs.
>

The networking stack shouldn't queue any new TX packets if the queue
is stopped - is this really worth complicating the code? Looks like
premature optimization IMO.

> It may also be faster to not mask/unmask at all but just
> clear the interrupts that you have finished processing
>

Bart

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

WARNING: multiple messages have this Message-ID (diff)
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Arnd Bergmann <arnd@arndb.de>
Cc: Edwin Peer <edwin.peer@broadcom.com>,
	DTML <devicetree@vger.kernel.org>,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>,
	Stephane Le Provost <stephane.leprovost@mediatek.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Networking <netdev@vger.kernel.org>,
	Sean Wang <sean.wang@mediatek.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Pedro Tsai <pedro.tsai@mediatek.com>,
	Mark Lee <Mark-MC.Lee@mediatek.com>,
	Fabien Parent <fparent@baylibre.com>,
	Rob Herring <robh+dt@kernel.org>,
	"moderated list:ARM/Mediatek SoC..."
	<linux-mediatek@lists.infradead.org>,
	Andrew Perepech <andrew.perepech@mediatek.com>,
	John Crispin <john@phrozen.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Jakub Kicinski <kuba@kernel.org>,
	"David S . Miller" <davem@davemloft.net>,
	Linux ARM <linux-arm-kernel@lists.infradead.org>,
	Heiner Kallweit <hkallweit1@gmail.com>
Subject: Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
Date: Fri, 15 May 2020 09:11:14 +0200	[thread overview]
Message-ID: <CAMRc=MeypzZBHo6dJGKm4JujYyejqHxtdo7Ts95DXuL0VuMYCw@mail.gmail.com> (raw)
In-Reply-To: <CAK8P3a3=xgbvqrSpCK5h96eRH32AA7xnoK2ossvT0-cLFLzmXA@mail.gmail.com>

czw., 14 maj 2020 o 18:19 Arnd Bergmann <arnd@arndb.de> napisał(a):
>
> On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> > family. For now we only support full-duplex.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Looks very nice overall. Just a few things I noticed, and some ideas
> that may or may not make sense:
>
> > +/* This is defined to 0 on arm64 in arch/arm64/include/asm/processor.h but
> > + * this IP doesn't work without this alignment being equal to 2.
> > + */
> > +#ifdef NET_IP_ALIGN
> > +#undef NET_IP_ALIGN
> > +#endif
> > +#define NET_IP_ALIGN                           2
>
> Maybe you should just define your own macro instead of replacing
> the normal one then?
>

I did in an earlier version and was told to use NET_IP_ALIGN but then
found out its value on arm64 doesn't work for me so I did the thing
that won't make anybody happy - redefine the existing constant. :)

> > +static void mtk_mac_lock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_lock_irqsave(&priv->lock, priv->lock_flags);
> > +}
> > +
> > +static void mtk_mac_unlock(struct mtk_mac_priv *priv)
> > +{
> > +       spin_unlock_irqrestore(&priv->lock, priv->lock_flags);
> > +}
>
> This looks wrong: you should not have shared 'flags' passed into
> spin_lock_irqsave(), and I don't even see a need to use the
> irqsave variant of the lock in the first place.
>
> Maybe start by open-coding the lock and remove the wrappers
> above.
>
> Then see if you can use a cheaper spin_lock_bh() or plain spin_lock()
> instead of irqsave.
>

This is from an earlier version where I did a lot more in hard irq
context. Now that almost all of the processing happens in soft-irq
context I guess you're right - I can go with a regular spin_lock().

> Finally, see if this can be done in a lockless way by relying on
> appropriate barriers and separating the writers into separate
> cache lines. From a brief look at the driver I think it can be done
> without too much trouble.
>

Unfortunately I do need some locking. Accessing RX and TX descriptors
at the same time seems to upset the controller. I experimented a lot
with barriers but it turned out that I got a lot of weird bugs at high
throughput.

> > +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> > +{
> > +       unsigned int val;
> > +
> > +       regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> > +       regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> > +
> > +       return val;
> > +}
>
> Do you actually need to read the register? That is usually a relatively
> expensive operation, so if possible try to use clear the bits when
> you don't care which bits were set.
>

I do care, I'm afraid. The returned value is being used in the napi
poll callback to see which ring to process.

> > +/* All processing for TX and RX happens in the napi poll callback. */
> > +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       struct net_device *ndev;
> > +
> > +       ndev = data;
> > +       priv = netdev_priv(ndev);
> > +
> > +       if (netif_running(ndev)) {
> > +               mtk_mac_intr_mask_all(priv);
> > +               napi_schedule(&priv->napi);
> > +       }
> > +
> > +       return IRQ_HANDLED;
>
>
> > +static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
> > +                                    struct net_device *ndev)
> > +{
> > +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct device *dev = mtk_mac_get_dev(priv);
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +
> > +       desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
> > +       if (dma_mapping_error(dev, desc_data.dma_addr))
> > +               goto err_drop_packet;
> > +
> > +       desc_data.skb = skb;
> > +       desc_data.len = skb->len;
> > +
> > +       mtk_mac_lock(priv);
> > +       mtk_mac_ring_push_head_tx(ring, &desc_data);
> > +
> > +       if (mtk_mac_ring_full(ring))
> > +               netif_stop_queue(ndev);
> > +       mtk_mac_unlock(priv);
> > +
> > +       mtk_mac_dma_resume_tx(priv);
> > +
> > +       return NETDEV_TX_OK;
> > +
> > +err_drop_packet:
> > +       dev_kfree_skb(skb);
> > +       ndev->stats.tx_dropped++;
> > +       return NETDEV_TX_BUSY;
> > +}
>
> I would always add BQL flow control in new drivers, using
> netdev_sent_queue here...
>

Ok, will do.

> > +static int mtk_mac_tx_complete_one(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct mtk_mac_ring_desc_data desc_data;
> > +       int ret;
> > +
> > +       ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> > +       if (ret)
> > +               return ret;
> > +
> > +       mtk_mac_dma_unmap_tx(priv, &desc_data);
> > +       dev_kfree_skb_irq(desc_data.skb);
> > +
> > +       return 0;
> > +}
>
> ... and netdev_completed_queue()  here.
>

Same here.

> > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > +{
> > +       struct mtk_mac_ring *ring = &priv->tx_ring;
> > +       struct net_device *ndev = priv->ndev;
> > +       int ret;
> > +
> > +       for (;;) {
> > +               mtk_mac_lock(priv);
> > +
> > +               if (!mtk_mac_ring_descs_available(ring)) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               ret = mtk_mac_tx_complete_one(priv);
> > +               if (ret) {
> > +                       mtk_mac_unlock(priv);
> > +                       break;
> > +               }
> > +
> > +               if (netif_queue_stopped(ndev))
> > +                       netif_wake_queue(ndev);
> > +
> > +               mtk_mac_unlock(priv);
> > +       }
> > +}
>
> It looks like most of the stuff inside of the loop can be pulled out
> and only done once here.
>

I did that in one of the previous submissions but it was pointed out
to me that a parallel TX path may fill up the queue before I wake it.

> > +static int mtk_mac_poll(struct napi_struct *napi, int budget)
> > +{
> > +       struct mtk_mac_priv *priv;
> > +       unsigned int status;
> > +       int received = 0;
> > +
> > +       priv = container_of(napi, struct mtk_mac_priv, napi);
> > +
> > +       status = mtk_mac_intr_read_and_clear(priv);
> > +
> > +       /* Clean up TX */
> > +       if (status & MTK_MAC_BIT_INT_STS_TNTC)
> > +               mtk_mac_tx_complete_all(priv);
> > +
> > +       /* Receive up to $budget packets */
> > +       if (status & MTK_MAC_BIT_INT_STS_FNRC)
> > +               received = mtk_mac_process_rx(priv, budget);
> > +
> > +       /* One of the counter reached 0x8000000 - update stats and reset all
> > +        * counters.
> > +        */
> > +       if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> > +               mtk_mac_update_stats(priv);
> > +               mtk_mac_reset_counters(priv);
> > +       }
> > +
> > +       if (received < budget)
> > +               napi_complete_done(napi, received);
> > +
> > +       mtk_mac_intr_unmask_all(priv);
> > +
> > +       return received;
> > +}
>
> I think you want to leave (at least some of) the interrupts masked
> if your budget is exhausted, to avoid generating unnecessary
> irqs.
>

The networking stack shouldn't queue any new TX packets if the queue
is stopped - is this really worth complicating the code? Looks like
premature optimization IMO.

> It may also be faster to not mask/unmask at all but just
> clear the interrupts that you have finished processing
>

Bart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-05-15  7:11 UTC|newest]

Thread overview: 78+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-14  7:59 [PATCH v3 00/15] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
2020-05-14  7:59 ` Bartosz Golaszewski
2020-05-14  7:59 ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 01/15] dt-bindings: convert the binding document for mediatek PERICFG to yaml Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 02/15] dt-bindings: add new compatible to mediatek,pericfg Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 03/15] dt-bindings: net: add a binding document for MediaTek Ethernet MAC Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 04/15] net: ethernet: mediatek: rename Kconfig prompt Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 05/15] net: ethernet: mediatek: remove unnecessary spaces from Makefile Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 06/15] Documentation: devres: add a missing section for networking helpers Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 07/15] net: move devres helpers into a separate source file Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 08/15] net: devres: define a separate devres structure for devm_alloc_etherdev() Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 09/15] net: devres: provide devm_register_netdev() Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14 16:19   ` Arnd Bergmann
2020-05-14 16:19     ` Arnd Bergmann
2020-05-14 16:19     ` Arnd Bergmann
2020-05-15  7:11     ` Bartosz Golaszewski [this message]
2020-05-15  7:11       ` Bartosz Golaszewski
2020-05-15  7:11       ` Bartosz Golaszewski
2020-05-15 12:04       ` Arnd Bergmann
2020-05-15 12:04         ` Arnd Bergmann
2020-05-15 12:04         ` Arnd Bergmann
2020-05-15 12:56         ` Bartosz Golaszewski
2020-05-15 12:56           ` Bartosz Golaszewski
2020-05-15 12:56           ` Bartosz Golaszewski
2020-05-15 13:11           ` Arnd Bergmann
2020-05-15 13:11             ` Arnd Bergmann
2020-05-15 13:11             ` Arnd Bergmann
2020-05-15 13:14       ` Andrew Lunn
2020-05-15 13:14         ` Andrew Lunn
2020-05-15 13:14         ` Andrew Lunn
2020-05-15 13:32   ` Arnd Bergmann
2020-05-15 13:32     ` Arnd Bergmann
2020-05-15 13:32     ` Arnd Bergmann
2020-05-18 14:07     ` Bartosz Golaszewski
2020-05-18 14:07       ` Bartosz Golaszewski
2020-05-18 14:07       ` Bartosz Golaszewski
2020-05-18 14:38       ` Arnd Bergmann
2020-05-18 14:38         ` Arnd Bergmann
2020-05-18 14:38         ` Arnd Bergmann
2020-05-14  7:59 ` [PATCH v3 11/15] ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 12/15] ARM64: dts: mediatek: add the ethernet node " Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 13/15] ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 14/15] ARM64: dts: mediatek: add ethernet pins " Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59 ` [PATCH v3 15/15] ARM64: dts: mediatek: enable ethernet on " Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14  7:59   ` Bartosz Golaszewski
2020-05-14 19:56 ` [PATCH v3 00/15] mediatek: add support for MediaTek Ethernet MAC David Miller
2020-05-14 19:56   ` David Miller
2020-05-14 19:56   ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAMRc=MeypzZBHo6dJGKm4JujYyejqHxtdo7Ts95DXuL0VuMYCw@mail.gmail.com' \
    --to=brgl@bgdev.pl \
    --cc=Mark-MC.Lee@mediatek.com \
    --cc=andrew.perepech@mediatek.com \
    --cc=arnd@arndb.de \
    --cc=bgolaszewski@baylibre.com \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=edwin.peer@broadcom.com \
    --cc=fparent@baylibre.com \
    --cc=hkallweit1@gmail.com \
    --cc=john@phrozen.org \
    --cc=kuba@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pedro.tsai@mediatek.com \
    --cc=robh+dt@kernel.org \
    --cc=sean.wang@mediatek.com \
    --cc=stephane.leprovost@mediatek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.