Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp1688749ybz; Thu, 16 Apr 2020 13:44:19 -0700 (PDT) X-Google-Smtp-Source: APiQypJAYzta+ZZezExMfgp78fS8JyJu6NKHrru20rnoYHqH4SXSMSPCbbmS58r7HxtNWz4sK2Nt X-Received: by 2002:a50:a685:: with SMTP id e5mr31515edc.243.1587069859326; Thu, 16 Apr 2020 13:44:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1587069859; cv=none; d=google.com; s=arc-20160816; b=0wYJf0xiVEcXzOyWQfYJisdn/yOVg3oubxRVBa7srpfxfQJJIlT8PAuOBZrz3Unqdb BQCLC5KDfpfo3qV5STq5rHVaabhABH8jNSo3MeAwbF0uWFKrDWIg1PW7DgyvyL06pJ92 kqy5BbGnEmL9TnXbNQl8PvGmjiSm47bbtjaXF42sEJozR8NaLCnCTFbOK5dSAtRanOOA tH7eUAtdzLoxUYDjfgxMZt8h4qn6MHiMGvpUsc8nmzEv/hgZDEIplaK8WdvB4WmcpDrJ XGf5aq/0D7h8iEYpVTq0Qbdmxe6WYysoa9GMU77jmgENZPzMQy/b3KvIUpUSQfpIjdFC AwVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :ironport-sdr:dkim-signature; bh=DNfziaevBEPYhAe/COLxbtO8IqIcfwelXIyifEzMkvI=; b=PoHuZnjfT4YqNIXsbOXK90/xm0H8xXr+R4D9k+g4FQmxSo/9z0rNHTZuPV42WYqyVL QkKsOmrHrYEH0YJwDWP8jjduBWVed2DJYZJd8YginPBknwbxBzmIaeSaDEOnfhtIWgs0 bb0UWo5WvKeO4251DgUt7hMiWxqR0TGFV23fOE5cWOg/v5xAb90zAYFDxdMNf9WdsKHg zxl4cKziFa+HAMdJv+IpzPxO+SN8jenDv31znfGsem4c3I1NR7m8T/i7cqLEWkWGmaKj Xenoo2xjO8YoPO/zTPT8rbiUP05wiRLn4Mcge0yOEDPn7THzEaM5FeYE5bh3T/BIcDjX SvsA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@microchip.com header.s=mchp header.b=gyZGaxlw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=microchip.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id x99si10528594ede.439.2020.04.16.13.43.55; Thu, 16 Apr 2020 13:44:19 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=fail header.i=@microchip.com header.s=mchp header.b=gyZGaxlw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=microchip.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2405217AbgDPRpb (ORCPT + 99 others); Thu, 16 Apr 2020 13:45:31 -0400 Received: from esa4.microchip.iphmx.com ([68.232.154.123]:40843 "EHLO esa4.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404312AbgDPRp3 (ORCPT ); Thu, 16 Apr 2020 13:45:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1587059128; x=1618595128; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=anuQUO7vMIZ2aAauy7qxz03g7SnCCMPbNtXr8rLKm0k=; b=gyZGaxlwwL5Gkf8FjAhOAJEeJ6Af6nOi9jUcWdegUap4Amt0PVpjAOaP KEI87xcrgNz3biAoNmjdzJ+02KTcvexFH9WZ4JrjQVkXdOW3T0XavHB2K Sq6aUcJNbhlU5/RvuSqA3IJa+YuMpBAHQPTvt17+S57kJ/ouFLbE2Cx6z gfwA+5quERamg8qfKKY2h07Y/2XYeawJgbVUZXyA6bJP41sXAVtny9eGa oJP4wskY6j5mjtnd4+c/Gne36E0EboTpeJsVjpDylPdljsW1x4INDJmx6 SuquO5OpPiQenMKw7+cY7T3oR/VtKe6FfZfWtNdwK1djss5srb684o2cK g==; IronPort-SDR: Z+1bSOAw2BfRjyvGZWf6vGcyPsN69D1o6YIR114kMXjfeFQKIRA7mpLmh3zEg009nqfbkPCnPF eZgYjf9Ocxg5gULSCMhAK7Nj5dbqS1LPz4BwEzfhdKikYMZnL9nCADSoT29dpHcKwG7nXaGCRR FxQByNQ+G6O4bjAWduNgUvYByu3ziYRqyObg7MXDguswbapEyJ0Zh2H9Plk4B6XVB5oNXc56og GHYpR9YkELSWywbynDR0XBM1p1sOgAg7PdMC+9epUtTL9JYvC2KhamwSSPPbrm/hU322WiFqOG KvM= X-IronPort-AV: E=Sophos;i="5.72,391,1580799600"; d="scan'208";a="70590692" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 16 Apr 2020 10:45:28 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Thu, 16 Apr 2020 10:45:32 -0700 Received: from ness.corp.atmel.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.1713.5 via Frontend Transport; Thu, 16 Apr 2020 10:45:21 -0700 From: To: , , "Claudiu Beznea" , CC: , "David S. Miller" , Alexandre Belloni , , , , , , , , Nicolas Ferre Subject: [PATCH 4/5] net: macb: WoL support for GEM type of Ethernet controller Date: Thu, 16 Apr 2020 19:44:31 +0200 Message-ID: <56bb7a742093cec160c4465c808778a14b2607e7.1587058078.git.nicolas.ferre@microchip.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Nicolas Ferre Adapt the Wake-on-Lan feature to the Cadence GEM Ethernet controller. This controller has different register layout and cannot be handled by previous code. We disable completely interrupts on all the queues but the queue 0. Handling of WoL interrupt is done in another interrupt handler positioned depending on the controller version used, just between suspend() and resume() calls. It allows to lower pressure on the generic interrupt hot path by removing the need to handle 2 tests for each IRQ: the first figuring out the controller revision, the second for actually knowing if the WoL bit is set. Queue management in suspend()/resume() functions inspired from RFC patch by Harini Katakam , thanks! Signed-off-by: Nicolas Ferre --- drivers/net/ethernet/cadence/macb.h | 3 + drivers/net/ethernet/cadence/macb_main.c | 121 ++++++++++++++++++++--- 2 files changed, 109 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index ab827fb4b6b9..4f1b41569260 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -90,6 +90,7 @@ #define GEM_SA3T 0x009C /* Specific3 Top */ #define GEM_SA4B 0x00A0 /* Specific4 Bottom */ #define GEM_SA4T 0x00A4 /* Specific4 Top */ +#define GEM_WOL 0x00b8 /* Wake on LAN */ #define GEM_EFTSH 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */ #define GEM_EFRSH 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */ #define GEM_PEFTSH 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */ @@ -396,6 +397,8 @@ #define MACB_PDRSFT_SIZE 1 #define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */ #define MACB_SRI_SIZE 1 +#define GEM_WOL_OFFSET 28 /* Enable wake-on-lan interrupt */ +#define GEM_WOL_SIZE 1 /* Timer increment fields */ #define MACB_TI_CNS_OFFSET 0 diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index b17a33c60cd4..71e6afbdfb47 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1513,6 +1513,34 @@ static void macb_tx_restart(struct macb_queue *queue) macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); } +static irqreturn_t gem_wol_interrupt(int irq, void *dev_id) +{ + struct macb_queue *queue = dev_id; + struct macb *bp = queue->bp; + u32 status; + + status = queue_readl(queue, ISR); + + if (unlikely(!status)) + return IRQ_NONE; + + spin_lock(&bp->lock); + + if (status & GEM_BIT(WOL)) { + queue_writel(queue, IDR, GEM_BIT(WOL)); + gem_writel(bp, WOL, 0); + netdev_vdbg(bp->dev, "GEM WoL: queue = %u, isr = 0x%08lx\n", + (unsigned int)(queue - bp->queues), + (unsigned long)status); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, GEM_BIT(WOL)); + } + + spin_unlock(&bp->lock); + + return IRQ_HANDLED; +} + static irqreturn_t macb_interrupt(int irq, void *dev_id) { struct macb_queue *queue = dev_id; @@ -3306,6 +3334,8 @@ static const struct ethtool_ops macb_ethtool_ops = { static const struct ethtool_ops gem_ethtool_ops = { .get_regs_len = macb_get_regs_len, .get_regs = macb_get_regs, + .get_wol = macb_get_wol, + .set_wol = macb_set_wol, .get_link = ethtool_op_get_link, .get_ts_info = macb_get_ts_info, .get_ethtool_stats = gem_get_ethtool_stats, @@ -4534,23 +4564,56 @@ static int __maybe_unused macb_suspend(struct device *dev) struct macb_queue *queue = bp->queues; unsigned long flags; unsigned int q; + int err; if (!netif_running(netdev)) return 0; if (bp->wol & MACB_WOL_ENABLED) { - macb_writel(bp, IER, MACB_BIT(WOL)); - macb_writel(bp, WOL, MACB_BIT(MAG)); - enable_irq_wake(bp->queues[0].irq); - netif_device_detach(netdev); - } else { - netif_device_detach(netdev); + spin_lock_irqsave(&bp->lock, flags); + /* Flush all status bits */ + macb_writel(bp, TSR, -1); + macb_writel(bp, RSR, -1); for (q = 0, queue = bp->queues; q < bp->num_queues; - ++q, ++queue) - napi_disable(&queue->napi); - rtnl_lock(); - phylink_stop(bp->phylink); - rtnl_unlock(); + ++q, ++queue) { + /* Disable all interrupts */ + queue_writel(queue, IDR, -1); + queue_readl(queue, ISR); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, -1); + } + /* Change interrupt handler and + * Enable WoL IRQ on queue 0 + */ + if (macb_is_gem(bp)) { + devm_free_irq(dev, bp->queues[0].irq, bp->queues); + err = devm_request_irq(dev, bp->queues[0].irq, gem_wol_interrupt, + IRQF_SHARED, netdev->name, bp->queues); + if (err) { + dev_err(dev, + "Unable to request IRQ %d (error %d)\n", + bp->queues[0].irq, err); + return err; + } + queue_writel(bp->queues, IER, GEM_BIT(WOL)); + gem_writel(bp, WOL, MACB_BIT(MAG)); + } else { + queue_writel(bp->queues, IER, MACB_BIT(WOL)); + macb_writel(bp, WOL, MACB_BIT(MAG)); + } + spin_unlock_irqrestore(&bp->lock, flags); + + enable_irq_wake(bp->queues[0].irq); + } + + netif_device_detach(netdev); + for (q = 0, queue = bp->queues; q < bp->num_queues; + ++q, ++queue) + napi_disable(&queue->napi); + + if (!(bp->wol & MACB_WOL_ENABLED)) { + phy_stop(netdev->phydev); + phy_suspend(netdev->phydev); spin_lock_irqsave(&bp->lock, flags); macb_reset_hw(bp); spin_unlock_irqrestore(&bp->lock, flags); @@ -4575,20 +4638,48 @@ static int __maybe_unused macb_resume(struct device *dev) struct net_device *netdev = dev_get_drvdata(dev); struct macb *bp = netdev_priv(netdev); struct macb_queue *queue = bp->queues; + unsigned long flags; unsigned int q; + int err; if (!netif_running(netdev)) return 0; pm_runtime_force_resume(dev); + macb_writel(bp, NCR, MACB_BIT(MPE)); + if (bp->wol & MACB_WOL_ENABLED) { - macb_writel(bp, IDR, MACB_BIT(WOL)); - macb_writel(bp, WOL, 0); + spin_lock_irqsave(&bp->lock, flags); + /* Disable WoL */ + if (macb_is_gem(bp)) { + queue_writel(bp->queues, IDR, GEM_BIT(WOL)); + gem_writel(bp, WOL, 0); + } else { + queue_writel(bp->queues, IDR, MACB_BIT(WOL)); + macb_writel(bp, WOL, 0); + } + /* Clear ISR on queue 0 */ + queue_readl(bp->queues, ISR); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(bp->queues, ISR, -1); + /* Replace interrupt handler on queue 0 */ + devm_free_irq(dev, bp->queues[0].irq, bp->queues); + err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt, + IRQF_SHARED, netdev->name, bp->queues); + if (err) { + dev_err(dev, + "Unable to request IRQ %d (error %d)\n", + bp->queues[0].irq, err); + return err; + } + spin_unlock_irqrestore(&bp->lock, flags); + disable_irq_wake(bp->queues[0].irq); + for (q = 0, queue = bp->queues; q < bp->num_queues; + ++q, ++queue) + napi_enable(&queue->napi); } else { - macb_writel(bp, NCR, MACB_BIT(MPE)); - if (netdev->hw_features & NETIF_F_NTUPLE) gem_writel_n(bp, ETHT, SCRT2_ETHT, bp->pm_data.scrt2); -- 2.20.1