From patchwork Wed Nov 23 12:48:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 24954 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp2787575wrr; Wed, 23 Nov 2022 05:28:19 -0800 (PST) X-Google-Smtp-Source: AA0mqf4LVyzBxU+ip7vXgLx9RsdniCVTjYpf0tsYmdVpZR1WJp2z8GZ1Zl/xGFFhZVIDVo9CBfFI X-Received: by 2002:a62:542:0:b0:56c:45db:4481 with SMTP id 63-20020a620542000000b0056c45db4481mr30064297pff.86.1669210098904; Wed, 23 Nov 2022 05:28:18 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669210098; cv=none; d=google.com; s=arc-20160816; b=xBdAQqxyGZDmxM9+9Noa6NPNzSwR+shXpfnYkpfgWciwKhw2/C3+/NYTs9mgx3/UdR wwTRKV8nys/KueDyrmNuwht7k+uUh9+E7wAnV6oewjOonsY6vTFnQ7LovNdn4NHEoUTQ bQhHpmf85a31Fb4WOy8cVX3UiCepfgo4jcrZt3/Kv22O0RmTw3wfNMQWOGT/xOocKpVk adGbWMLuESr50+7NaEEbOg6yy43xhzYej4FQlA1UyAl9UY8FZem7ZW87qAHK50Lc1C0z BDvygojLfVKk1COsvXI6ctOn24SggK3h/SV9oLAJWhIZ712z2gCblQG3RV6u4J/enZjK mNEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:dkim-signature; bh=gUimLy3I+iV2hErA9BbZWA3mO9haSOXalkNAYNcAtkY=; b=i0H234pR68IkqUTxPq0fflUm4oOFLP6Rflo1Sd0gwoYsVS0EluOEJ72S9oLEYl2xFe 7muCMh1Jr/djuUWXy9lKR1COyF4bdJ0GJFuCCBDZ/O7m5hSgi+l10oiabjkTlHphJYqL fwx0JuAMQKErNWqgAQjXYlEzyLJ7bPkFex3e5B1qpB+h9xw1lgooRCW0F3otm5X4C1rA grIX/KoLL35JrzqL2cL/H9wWTyRMEZEkXVrjVgBTxtkH7AA+YOZ5m7lujkWL/AO/NX+5 njjGLVDEEPwvdiiO8BtcWSqnFsDKgRwCeNWGGWoK5Hb3l4lxyoAX6g26Wpnrcm9ucupd 5tZA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=X9k1NHLJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 16-20020a17090a0b9000b00218cf92fc62si1508365pjr.89.2022.11.23.05.28.05; Wed, 23 Nov 2022 05:28:18 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=X9k1NHLJ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238693AbiKWNEs (ORCPT + 99 others); Wed, 23 Nov 2022 08:04:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238646AbiKWNEU (ORCPT ); Wed, 23 Nov 2022 08:04:20 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E320172985; Wed, 23 Nov 2022 04:48:58 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id CCA3561C81; Wed, 23 Nov 2022 12:48:53 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id CADB5C433D6; Wed, 23 Nov 2022 12:48:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1669207733; bh=LamfmSe/9C2Q/ScikvZ3rt5zy3hv55+2DVyzODZxWmA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X9k1NHLJqvPLfMRbZB3xazLNOfFfTd0wpk2Myc2TSUqJ0Nejy3Y6x9jAErbkCe4uo UrOblEkXzrVUcpWaFSDxUNRCjalYogz7D+noVC0BacRXPS/liLRbAbyC+mIOYatsAY sujFm+b11KcvHWKrjZyeE/ZvKJPdIGPhA84Uf3qsVK2H/xw7WyUfuHUVLxU9cHH0f8 Yl8zwpU9rMMleCuRTXZ1QlvbYSYHmpKCfNdmygg4OB8hcawXpiMRrdHkBPQJWHBiyr CWkA2iyTbob1dWpd7+9g0Hmtpyrxuvo2fzY/zRi7kxdnsUYZYqTm6NngixsloVRGaN 8N7Bp4Iw++6kw== From: Roger Quadros To: davem@davemloft.net, maciej.fijalkowski@intel.com, kuba@kernel.org Cc: edumazet@google.com, pabeni@redhat.com, vigneshr@ti.com, linux-omap@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Roger Quadros Subject: [PATCH v3 net-next 4/6] net: ethernet: ti: am65-cpsw: Add suspend/resume support Date: Wed, 23 Nov 2022 14:48:33 +0200 Message-Id: <20221123124835.18937-5-rogerq@kernel.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20221123124835.18937-1-rogerq@kernel.org> References: <20221123124835.18937-1-rogerq@kernel.org> X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750293648870112246?= X-GMAIL-MSGID: =?utf-8?q?1750293648870112246?= Add PM handlers for System suspend/resume. As DMA driver doesn't yet support suspend/resume we free up the DMA channels at suspend and acquire and initialize them at resume. In this revised approach we do not free the TX/RX IRQs at am65_cpsw_nuss_common_stop() as it causes problems. We will now free them only on .suspend() as we need to release the DMA channels (as DMA looses context) and re-acquiring them on .resume() may not necessarily give us the same IRQs. To make this easier: - introduce am65_cpsw_nuss_remove_rx_chns() which is similar to am65_cpsw_nuss_remove_tx_chns(). These will be invoked in pm.suspend() to release the DMA channels and free up the IRQs. - move napi_add() and request_irq() calls to am65_cpsw_nuss_init_rx/tx_chns() so we can invoke them in pm.resume() to acquire the DMA channels and IRQs. As CPTS looses contect during suspend/resume, invoke the necessary CPTS suspend/resume helpers. ALE_CLEAR command is issued in cpsw_ale_start() so no need to issue it before the call to cpsw_ale_start(). Signed-off-by: Roger Quadros --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 170 ++++++++++++++++++++--- 1 file changed, 147 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 4836960b0dd8..0b59088e3728 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -132,6 +133,8 @@ NETIF_MSG_IFUP | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | \ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) +static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common); + static void am65_cpsw_port_set_sl_mac(struct am65_cpsw_port *slave, const u8 *dev_addr) { @@ -555,11 +558,24 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) struct am65_cpsw_common *common = am65_ndev_to_common(ndev); struct am65_cpsw_port *port = am65_ndev_to_port(ndev); int ret, i; + u32 reg; ret = pm_runtime_resume_and_get(common->dev); if (ret < 0) return ret; + /* Idle MAC port */ + cpsw_sl_ctl_set(port->slave.mac_sl, CPSW_SL_CTL_CMD_IDLE); + cpsw_sl_wait_for_idle(port->slave.mac_sl, 100); + cpsw_sl_ctl_reset(port->slave.mac_sl); + + /* soft reset MAC */ + cpsw_sl_reg_write(port->slave.mac_sl, CPSW_SL_SOFT_RESET, 1); + mdelay(1); + reg = cpsw_sl_reg_read(port->slave.mac_sl, CPSW_SL_SOFT_RESET); + if (reg) + dev_info(common->dev, "mac reset not yet done\n"); + /* Notify the stack of the actual queue counts. */ ret = netif_set_real_num_tx_queues(ndev, common->tx_ch_num); if (ret) { @@ -1599,6 +1615,12 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common) dev_name(dev), tx_chn->id); } + ret = am65_cpsw_nuss_ndev_add_tx_napi(common); + if (ret) { + dev_err(dev, "Failed to add tx NAPI %d\n", ret); + goto err; + } + err: i = devm_add_action(dev, am65_cpsw_nuss_free_tx_chns, common); if (i) { @@ -1623,6 +1645,29 @@ static void am65_cpsw_nuss_free_rx_chns(void *data) k3_udma_glue_release_rx_chn(rx_chn->rx_chn); } +static void am65_cpsw_nuss_remove_rx_chns(void *data) +{ + struct am65_cpsw_common *common = data; + struct am65_cpsw_rx_chn *rx_chn; + struct device *dev = common->dev; + + rx_chn = &common->rx_chns; + devm_remove_action(dev, am65_cpsw_nuss_free_rx_chns, common); + + if (!(rx_chn->irq < 0)) + devm_free_irq(dev, rx_chn->irq, common); + + netif_napi_del(&common->napi_rx); + + if (!IS_ERR_OR_NULL(rx_chn->desc_pool)) + k3_cppi_desc_pool_destroy(rx_chn->desc_pool); + + if (!IS_ERR_OR_NULL(rx_chn->rx_chn)) + k3_udma_glue_release_rx_chn(rx_chn->rx_chn); + + common->rx_flow_id_base = -1; +} + static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common) { struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns; @@ -1710,6 +1755,18 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common) } } + netif_napi_add(common->dma_ndev, &common->napi_rx, + am65_cpsw_nuss_rx_poll); + + ret = devm_request_irq(dev, rx_chn->irq, + am65_cpsw_nuss_rx_irq, + IRQF_TRIGGER_HIGH, dev_name(dev), common); + if (ret) { + dev_err(dev, "failure requesting rx irq %u, %d\n", + rx_chn->irq, ret); + goto err; + } + err: i = devm_add_action(dev, am65_cpsw_nuss_free_rx_chns, common); if (i) { @@ -1981,6 +2038,7 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) port->slave.phylink_config.dev = &port->ndev->dev; port->slave.phylink_config.type = PHYLINK_NETDEV; port->slave.phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + port->slave.phylink_config.mac_managed_pm = true; /* MAC does PM */ if (phy_interface_mode_is_rgmii(port->slave.phy_if)) { phy_interface_set_rgmii(port->slave.phylink_config.supported_interfaces); @@ -2034,9 +2092,6 @@ static int am65_cpsw_nuss_init_ndevs(struct am65_cpsw_common *common) return ret; } - netif_napi_add(common->dma_ndev, &common->napi_rx, - am65_cpsw_nuss_rx_poll); - return ret; } @@ -2528,18 +2583,13 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common) struct am65_cpsw_port *port; int ret = 0, i; - ret = am65_cpsw_nuss_ndev_add_tx_napi(common); + /* init tx channels */ + ret = am65_cpsw_nuss_init_tx_chns(common); if (ret) return ret; - - ret = devm_request_irq(dev, common->rx_chns.irq, - am65_cpsw_nuss_rx_irq, - IRQF_TRIGGER_HIGH, dev_name(dev), common); - if (ret) { - dev_err(dev, "failure requesting rx irq %u, %d\n", - common->rx_chns.irq, ret); + ret = am65_cpsw_nuss_init_rx_chns(common); + if (ret) return ret; - } ret = am65_cpsw_nuss_register_devlink(common); if (ret) @@ -2584,10 +2634,8 @@ int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx) common->tx_ch_num = num_tx; ret = am65_cpsw_nuss_init_tx_chns(common); - if (ret) - return ret; - return am65_cpsw_nuss_ndev_add_tx_napi(common); + return ret; } struct am65_cpsw_soc_pdata { @@ -2736,14 +2784,6 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) am65_cpsw_nuss_get_ver(common); - /* init tx channels */ - ret = am65_cpsw_nuss_init_tx_chns(common); - if (ret) - goto err_of_clear; - ret = am65_cpsw_nuss_init_rx_chns(common); - if (ret) - goto err_of_clear; - ret = am65_cpsw_nuss_init_host_p(common); if (ret) goto err_of_clear; @@ -2828,10 +2868,94 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int am65_cpsw_nuss_suspend(struct device *dev) +{ + struct am65_cpsw_common *common = dev_get_drvdata(dev); + struct am65_cpsw_port *port; + struct net_device *ndev; + int i, ret; + + for (i = 0; i < common->port_num; i++) { + port = &common->ports[i]; + ndev = port->ndev; + + if (!ndev) + continue; + + netif_device_detach(ndev); + if (netif_running(ndev)) { + rtnl_lock(); + ret = am65_cpsw_nuss_ndo_slave_stop(ndev); + rtnl_unlock(); + if (ret < 0) { + netdev_err(ndev, "failed to stop: %d", ret); + return ret; + } + } + } + + am65_cpts_suspend(common->cpts); + + am65_cpsw_nuss_remove_rx_chns(common); + am65_cpsw_nuss_remove_tx_chns(common); + + return 0; +} + +static int am65_cpsw_nuss_resume(struct device *dev) +{ + struct am65_cpsw_common *common = dev_get_drvdata(dev); + struct am65_cpsw_port *port; + struct net_device *ndev; + int i, ret; + + ret = am65_cpsw_nuss_init_tx_chns(common); + if (ret) + return ret; + ret = am65_cpsw_nuss_init_rx_chns(common); + if (ret) + return ret; + + /* If RX IRQ was disabled before suspend, keep it disabled */ + if (common->rx_irq_disabled) + disable_irq(common->rx_chns.irq); + + am65_cpts_resume(common->cpts); + + for (i = 0; i < common->port_num; i++) { + port = &common->ports[i]; + ndev = port->ndev; + + if (!ndev) + continue; + + if (netif_running(ndev)) { + rtnl_lock(); + ret = am65_cpsw_nuss_ndo_slave_open(ndev); + rtnl_unlock(); + if (ret < 0) { + netdev_err(ndev, "failed to start: %d", ret); + return ret; + } + } + + netif_device_attach(ndev); + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops am65_cpsw_nuss_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(am65_cpsw_nuss_suspend, am65_cpsw_nuss_resume) +}; + static struct platform_driver am65_cpsw_nuss_driver = { .driver = { .name = AM65_CPSW_DRV_NAME, .of_match_table = am65_cpsw_nuss_of_mtable, + .pm = &am65_cpsw_nuss_dev_pm_ops, }, .probe = am65_cpsw_nuss_probe, .remove = am65_cpsw_nuss_remove,