From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5909AC433F5 for ; Tue, 28 Dec 2021 11:44:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Date:Subject:Cc:To:From:Message-ID:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=x1cbpmNyeah7eZyFWrh9HxvUUImnMFJkKh7QbCemcVc=; b=sjU5xVyvy75q5S ZDCmxtmTZkeKIXq0J2V12cBsVlyiTm9fW0A3rh28nrywDTTNR0q0lA0/yqp0WioK5zBmvaXAlXgMi TfadG8uXPR1FFjApgFDYz3jeIZehUn69BRZi5NT2qmzY6/yiNc3jvwHg08tjZbQnSrIVT42YWBt3Y ofSRGFEdA+MUNTB29i16gbeje1RVt05w4/Hwkl8y8oYYrrsdID84tdsdlSqnYdUHGDRww1m9HuLdo dZSOyPP6Ax0OAClLSVQVIR48jNDwic9OI5fixyCZPaDw/aBxL6NpN9l7XHkVMaAKkKBu+J9hKA4hU 7DOa/8sOH+1AILd+ckfQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1n2Ary-000p4d-M5; Tue, 28 Dec 2021 11:42:18 +0000 Received: from out203-205-221-149.mail.qq.com ([203.205.221.149]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1n2Aru-000p4H-2q for linux-arm-kernel@lists.infradead.org; Tue, 28 Dec 2021 11:42:17 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1640691727; bh=vt1DyY9j7CKuuiOii1kFg8ag3vshDK+zIcl/9FHQOP8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=sw9ZoeKW7XhFW1dN5SzGowXrXTXcEIHhX+SkSj2dx8kkYyAnNbpnQh/AeIKhHM6Uz MCXnt/R2I7hHUfkP4b+k0RGXkVoCaZRSqQzUc7M4441KK7cjSHIsxzDEVEIAt0pp4/ VEFBAT3yQLLWvzF6fSHieC/KMbriqGhL6YZVwyAo= Received: from fedora.. ([119.33.249.242]) by newxmesmtplogicsvrszc6.qq.com (NewEsmtp) with SMTP id A859F4D4; Tue, 28 Dec 2021 19:42:05 +0800 X-QQ-mid: xmsmtpt1640691725tav4kdg3q Message-ID: X-QQ-XMAILINFO: MxUBm8splV+pZAisvUjWjEqdH1U0TfAcZB/5PlnSfr4hicjvKs7k//ugkkBAXM n1ZaY9hJTrrZxxpndxrxpVVOpIwp/LpxZuX/dVQTnFd0xjbLBCxmta2R3+46fT7vUQdCYR0n+Vo9 MyRl/+NbYBh57M2Irp5G/7Aj4L6p81KPudInGxfWfwvlbdV/+jquxJAnd9yVvDULjKtHQcsfdc+4 e0naG4QUP6ZJjndWHbe4EAJqAv6rDal+L/C9ri3y1Ey7HpmTcr7whn0hzOCIhd5ZaL5tDAAk+FFw PChHN+coeR3ZvEo6ncrZRVfmFxTZ3MBthJV+Da4x+IcDgLEr9zt7dUkRfw0JYrjZzkOL/VV9AKjb 31f0gdaa/1Xiy+P4gebwMFAG7tPTrgYnVKeqYxKTyYyRRIFj05QLqchBJ4Y8P6/kGberlLXMC62x hyzxYgBWpfuf9YKmZCfot28eriLLGz1Wttes9fI22gsVLmiVOv+3Lbb5wVX5MjK14K53Vj0CI/kW 5NtZnu00Fig3jA+JbkcFgOECDMLL84pXYqN2UywXjUREFSkll9URkY57OIfNxRyrSRcBXB9A2CBx xd7GRSLoDW3QE0pbg+9oi5BdMS6l0wuG3vlzoU78jZ12wwL5IQP5+BcBRKEKg8T8AYt+4ZUAhG5H q153yAL3Gu9vre6Q5ykLC2GvjWGTI/BDyjJ7sRpkgfeNVh9wzhVnc8enK0byPJcFEL7ZQYHrI2kO DmUZDQ8eDCzh7R3VzvR6CuZ5C3H0JvseYd2WsLCCrJ91yfFG/N+nrPgNvTKFdmwR432OM7t3v6dp 1Glp+f+Cuz8Ge49B7kMDgd4bnfdpvg/3QjKOnmIu550T3PLQ0eScZCmuQakuijtassujy8WDSU48 QM7mgUmsZlqF/70kEbo1uzoxrmscstsA== From: conleylee@foxmail.com To: davem@davemloft.net, kuba@kernel.org, mripard@kernel.org, wens@csie.org Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Conley Lee Subject: [PATCH v5] sun4i-emac.c: add dma support Date: Tue, 28 Dec 2021 19:42:04 +0800 X-OQ-MSGID: <20211228114204.293243-1-conleylee@foxmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211228_034214_541122_D6F2DA70 X-CRM114-Status: GOOD ( 23.30 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Conley Lee Thanks for your review. Here is the new version for this patch. 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. Change since v4. - rename sbk field to skb - rename alloc_emac_dma_req to emac_alloc_dma_req - using kzalloc(..., GPF_ATOMIC) in interrupt context to avoid sleeping - retry by using emac_inblk_32bit when emac_dma_inblk_32bit fails - fix some code style issues Signed-off-by: Conley Lee --- drivers/net/ethernet/allwinner/sun4i-emac.c | 202 +++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index cccf8a3ead5e..ec8184196377 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -29,6 +29,7 @@ #include #include #include +#include #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 *skb; + dma_addr_t rxbuf; + int count; }; static void emac_update_speed(struct net_device *dev) @@ -205,6 +216,117 @@ 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 * +emac_alloc_dma_req(struct emac_board_info *db, + struct dma_async_tx_descriptor *desc, struct sk_buff *skb, + dma_addr_t rxbuf, int count) +{ + struct emac_dma_req *req; + + req = kzalloc(sizeof(struct emac_dma_req), GFP_ATOMIC); + if (!req) + return NULL; + + req->db = db; + req->desc = desc; + req->skb = 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->skb; + 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 */ + 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 int emac_dma_inblk_32bit(struct emac_board_info *db, + struct sk_buff *skb, void *rdptr, int count) +{ + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + dma_addr_t rxbuf; + struct emac_dma_req *req; + int ret = 0; + + rxbuf = dma_map_single(db->dev, rdptr, count, DMA_FROM_DEVICE); + ret = dma_mapping_error(db->dev, rxbuf); + if (ret) { + dev_err(db->dev, "dma mapping error.\n"); + return ret; + } + + 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"); + ret = -ENOMEM; + goto prepare_err; + } + + req = emac_alloc_dma_req(db, desc, skb, rxbuf, count); + if (!req) { + dev_err(db->dev, "alloc emac dma req error.\n"); + ret = -ENOMEM; + goto alloc_req_err; + } + + desc->callback_param = req; + desc->callback = emac_dma_done_callback; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dev_err(db->dev, "dma submit error.\n"); + goto submit_err; + } + + dma_async_issue_pending(db->rx_chan); + return ret; + +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); + return ret; +} + /* ethtool ops */ static void emac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -599,12 +721,25 @@ static void emac_rx(struct net_device *dev) if (!skb) continue; skb_reserve(skb, 2); - rdptr = skb_put(skb, rxlen - 4); /* Read received packet from RX SRAM */ if (netif_msg_rx_status(db)) dev_dbg(db->dev, "RxLen %x\n", rxlen); + rdptr = skb_put(skb, rxlen - 4); + if (rxlen >= dev->mtu && db->rx_chan) { + 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); + if (!emac_dma_inblk_32bit(db, skb, rdptr, rxlen)) + break; + + /* re enable cpu receive. then try to receive by emac_inblk_32bit */ + 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_inblk_32bit(db->membase + EMAC_RX_IO_DATA_REG, rdptr, rxlen); dev->stats.rx_bytes += rxlen; @@ -659,7 +794,12 @@ static irqreturn_t emac_interrupt(int irq, void *dev_id) reg_val = readl(db->membase + EMAC_INT_CTL_REG); reg_val |= (0xf << 0) | (0x01 << 8); writel(reg_val, db->membase + EMAC_INT_CTL_REG); + } else { + reg_val = readl(db->membase + EMAC_INT_CTL_REG); + reg_val |= (0xf << 0); + writel(reg_val, db->membase + EMAC_INT_CTL_REG); } + spin_unlock(&db->lock); return IRQ_HANDLED; @@ -764,6 +904,58 @@ static const struct net_device_ops emac_netdev_ops = { #endif }; +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\n"); + err = PTR_ERR(db->rx_chan); + goto out_clear_chan; + } + + conf.direction = DMA_DEV_TO_MEM; + conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + conf.src_addr = db->emac_rx_fifo; + conf.dst_maxburst = 4; + conf.src_maxburst = 4; + conf.device_fc = false; + + err = dmaengine_slave_config(db->rx_chan, &conf); + if (err) { + netdev_err(ndev, "config dma slave failed\n"); + err = -EINVAL; + goto out_slave_configure_err; + } + + return err; + +out_slave_configure_err: + dma_release_channel(db->rx_chan); + +out_clear_chan: + db->rx_chan = NULL; + return err; +} + /* Search EMAC board, allocate space and register it */ static int emac_probe(struct platform_device *pdev) @@ -806,6 +998,9 @@ static int emac_probe(struct platform_device *pdev) goto out_iounmap; } + if (emac_configure_dma(db)) + netdev_info(ndev, "configure dma failed. disable dma.\n"); + db->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(db->clk)) { ret = PTR_ERR(db->clk); @@ -888,6 +1083,11 @@ static int emac_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct emac_board_info *db = netdev_priv(ndev); + if (db->rx_chan) { + dmaengine_terminate_all(db->rx_chan); + dma_release_channel(db->rx_chan); + } + unregister_netdev(ndev); sunxi_sram_release(&pdev->dev); clk_disable_unprepare(db->clk); -- 2.31.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel