netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: conleylee@foxmail.com
Cc: davem@davemloft.net, mripard@kernel.org, wens@csie.org,
	netdev@vger.kernel.org
Subject: Re: [PATCH v4] sun4i-emac.c: add dma support
Date: Mon, 27 Dec 2021 18:35:41 -0800	[thread overview]
Message-ID: <20211227183541.3a9f2963@kicinski-fedora-PC1C0HJN.hsd1.ca.comcast.net> (raw)
In-Reply-To: <tencent_95A0609A0DC523F7DDAE60A8746EABAA8905@qq.com>

On Fri, 24 Dec 2021 22:44:31 +0800 conleylee@foxmail.com wrote:
> From: Conley Lee <conleylee@foxmail.com>
> 
> This patch adds support for the emac rx dma present on sun4i.
> The emac is able to move packets from rx fifo to RAM by using dma.
> 
> Signed-off-by: Conley Lee <conleylee@foxmail.com>
> ---
>  drivers/net/ethernet/allwinner/sun4i-emac.c | 209 +++++++++++++++++++-
>  1 file changed, 200 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
> index cccf8a3ead5e..b17d2df17335 100644
> --- a/drivers/net/ethernet/allwinner/sun4i-emac.c
> +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
> @@ -29,6 +29,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/phy.h>
>  #include <linux/soc/sunxi/sunxi_sram.h>
> +#include <linux/dmaengine.h>
>  
>  #include "sun4i-emac.h"
>  
> @@ -86,6 +87,16 @@ struct emac_board_info {
>  	unsigned int		duplex;
>  
>  	phy_interface_t		phy_interface;
> +	struct dma_chan	*rx_chan;
> +	phys_addr_t emac_rx_fifo;
> +};
> +
> +struct emac_dma_req {
> +	struct emac_board_info *db;
> +	struct dma_async_tx_descriptor *desc;
> +	struct sk_buff *sbk;

sbk -> skb ?

> +	dma_addr_t rxbuf;
> +	int count;
>  };
>  
>  static void emac_update_speed(struct net_device *dev)
> @@ -205,6 +216,113 @@ static void emac_inblk_32bit(void __iomem *reg, void *data, int count)
>  	readsl(reg, data, round_up(count, 4) / 4);
>  }
>  
> +static struct emac_dma_req *
> +alloc_emac_dma_req(struct emac_board_info *db,

nit: please use "emac" as a prefix of the name, instead of putting it
     inside the name.

> +		   struct dma_async_tx_descriptor *desc, struct sk_buff *skb,
> +		   dma_addr_t rxbuf, int count)
> +{
> +	struct emac_dma_req *req =
> +		kzalloc(sizeof(struct emac_dma_req), GFP_KERNEL);

Please don't put complex initializers inline, also missing an empty
line between variable declaration and code. Should be:

	struct emac_dma_req *req;

	req = kzalloc(...);
	if (!req)
		...

You seem to call this from an IRQ handler, shouldn't the flags be
GFP_ATOMIC? Please test with CONFIG_DEBUG_ATOMIC_SLEEP=y.

> +	if (!req)
> +		return NULL;
> +
> +	req->db = db;
> +	req->desc = desc;
> +	req->sbk = skb;
> +	req->rxbuf = rxbuf;
> +	req->count = count;
> +	return req;
> +}
> +
> +static void free_emac_dma_req(struct emac_dma_req *req)
> +{
> +	kfree(req);
> +}
> +
> +static void emac_dma_done_callback(void *arg)
> +{
> +	struct emac_dma_req *req = arg;
> +	struct emac_board_info *db = req->db;
> +	struct sk_buff *skb = req->sbk;
> +	struct net_device *dev = db->ndev;
> +	int rxlen = req->count;
> +	u32 reg_val;
> +
> +	dma_unmap_single(db->dev, req->rxbuf, rxlen, DMA_FROM_DEVICE);
> +
> +	skb->protocol = eth_type_trans(skb, dev);
> +	netif_rx(skb);
> +	dev->stats.rx_bytes += rxlen;
> +	/* Pass to upper layer */
> +	dev->stats.rx_packets++;
> +
> +	//re enable cpu receive

Please use the /**/ comment style consistently

> +	reg_val = readl(db->membase + EMAC_RX_CTL_REG);
> +	reg_val &= ~EMAC_RX_CTL_DMA_EN;
> +	writel(reg_val, db->membase + EMAC_RX_CTL_REG);
> +
> +	//re enable interrupt
> +	reg_val = readl(db->membase + EMAC_INT_CTL_REG);
> +	reg_val |= (0x01 << 8);
> +	writel(reg_val, db->membase + EMAC_INT_CTL_REG);
> +
> +	db->emacrx_completed_flag = 1;
> +	free_emac_dma_req(req);
> +}
> +
> +static void emac_dma_inblk_32bit(struct emac_board_info *db,
> +				 struct sk_buff *skb, int count)
> +{
> +	struct dma_async_tx_descriptor *desc;
> +	dma_cookie_t cookie;
> +	dma_addr_t rxbuf;
> +	void *rdptr;
> +	struct emac_dma_req *req;
> +
> +	rdptr = skb_put(skb, count - 4);

The skb_put can be factored out from both branches it seems.

> +	rxbuf = dma_map_single(db->dev, rdptr, count, DMA_FROM_DEVICE);
> +
> +	if (dma_mapping_error(db->dev, rxbuf)) {
> +		dev_err(db->dev, "dma mapping error.\n");
> +		return;

You seem to leak the skb if this function fails, no?

> +	}
> +
> +	desc = dmaengine_prep_slave_single(db->rx_chan, rxbuf, count,
> +					   DMA_DEV_TO_MEM,
> +					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +	if (!desc) {
> +		dev_err(db->dev, "prepare slave single failed\n");
> +		goto prepare_err;
> +	}
> +
> +	req = alloc_emac_dma_req(db, desc, skb, rxbuf, count);
> +	if (!req) {
> +		dev_err(db->dev, "alloc emac dma req error.\n");
> +		goto alloc_req_err;
> +	}
> +
> +	desc->callback_param = req;
> +	desc->callback = emac_dma_done_callback;
> +
> +	cookie = dmaengine_submit(desc);
> +	if (dma_submit_error(cookie)) {
> +		dev_err(db->dev, "dma submit error.\n");
> +		goto submit_err;
> +	}
> +
> +	dma_async_issue_pending(db->rx_chan);
> +	return;
> +
> +submit_err:
> +	free_emac_dma_req(req);
> +
> +alloc_req_err:
> +	dmaengine_desc_free(desc);
> +
> +prepare_err:
> +	dma_unmap_single(db->dev, rxbuf, count, DMA_FROM_DEVICE);
> +}

> -			/* Pass to upper layer */
> -			skb->protocol = eth_type_trans(skb, dev);
> -			netif_rx(skb);
> -			dev->stats.rx_packets++;
> +			if (rxlen < dev->mtu || !db->rx_chan) {
> +				rdptr = skb_put(skb, rxlen - 4);
> +				emac_inblk_32bit(db->membase + EMAC_RX_IO_DATA_REG,
> +						rdptr, rxlen);
> +				dev->stats.rx_bytes += rxlen;
> +
> +				/* Pass to upper layer */
> +				skb->protocol = eth_type_trans(skb, dev);
> +				netif_rx(skb);
> +				dev->stats.rx_packets++;
> +			} else {
> +				reg_val = readl(db->membase + EMAC_RX_CTL_REG);
> +				reg_val |= EMAC_RX_CTL_DMA_EN;
> +				writel(reg_val, db->membase + EMAC_RX_CTL_REG);
> +				emac_dma_inblk_32bit(db, skb, rxlen);
> +				break;
> +			}
>  		}

> +static int emac_configure_dma(struct emac_board_info *db)
> +{
> +	struct platform_device *pdev = db->pdev;
> +	struct net_device *ndev = db->ndev;
> +	struct dma_slave_config conf = {};
> +	struct resource *regs;
> +	int err = 0;
> +
> +	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!regs) {
> +		netdev_err(ndev, "get io resource from device failed.\n");
> +		err = -ENOMEM;
> +		goto out_clear_chan;
> +	}
> +
> +	netdev_info(ndev, "get io resource from device: 0x%x, size = %u\n",
> +		    regs->start, resource_size(regs));
> +	db->emac_rx_fifo = regs->start + EMAC_RX_IO_DATA_REG;
> +
> +	db->rx_chan = dma_request_chan(&pdev->dev, "rx");
> +	if (IS_ERR(db->rx_chan)) {
> +		netdev_err(ndev,
> +			   "failed to request dma channel. dma is disabled");

nit: this message lacks '\n' at the end

> +		err = PTR_ERR(db->rx_chan);
> +		goto out_clear_chan;
> +	}


  reply	other threads:[~2021-12-28  2:35 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-24 14:44 [PATCH v4] sun4i-emac.c: add dma support conleylee
2021-12-28  2:35 ` Jakub Kicinski [this message]
     [not found] ` <tencent_A7052D6C7B1E2AEFA505D7A52E5B974D8508@qq.com>
2021-12-29  0:48   ` [PATCH v5] " Jakub Kicinski
2021-12-29  1:43     ` [PATCH v6] " conleylee
2021-12-30  2:00       ` patchwork-bot+netdevbpf
2022-05-30  4:51         ` Corentin Labbe
2022-05-30 18:48           ` Jakub Kicinski
2022-05-30 18:55             ` Corentin Labbe
2021-12-31 10:43       ` Corentin Labbe
     [not found]         ` <tencent_57960DDC83F43DA3E0A2F47DEBAD69A4A005@qq.com>
2022-01-02 17:38           ` Corentin Labbe
     [not found]             ` <tencent_67023336008FE777A58293D2D32DEFA69107@qq.com>
2022-01-03 11:42               ` Corentin Labbe
2022-01-03 12:21                 ` Conley Lee
     [not found]                 ` <tencent_E4BA4D6105A46CCC1E8AEF48057EA5FE5B08@qq.com>
2022-01-09 20:45                   ` [PATCH v1] sun4i-emac.c: enable emac tx dma Corentin Labbe
2022-01-10  7:47                     ` Conley Lee
2022-01-07 23:34       ` [PATCH v6] sun4i-emac.c: add dma support Kees Cook
2022-01-08  2:34         ` Jakub Kicinski

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=20211227183541.3a9f2963@kicinski-fedora-PC1C0HJN.hsd1.ca.comcast.net \
    --to=kuba@kernel.org \
    --cc=conleylee@foxmail.com \
    --cc=davem@davemloft.net \
    --cc=mripard@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=wens@csie.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).