net: macb: save/restore the remaining registers and features [Linux 5.2]

net: macb: save/restore the remaining registers and features [Linux 5.2]

This Linux kernel change "net: macb: save/restore the remaining registers and features" is included in the Linux 5.2 release. This change is authored by Claudiu Beznea <claudiu.beznea [at] microchip.com> on Wed May 22 08:24:43 2019 +0000. The commit for this change in Linux stable tree is c1e85c6 (patch).

net: macb: save/restore the remaining registers and features

SAMA5D2 SoC has a suspend mode where SoC's power is cut off. Due to this
the registers content is lost after a suspend/resume cycle. The current
suspend/resume implementation covers some of these registers. However
there are few which were not treated (e.g. SCRT2 and USRIO). Apart
from this, netdev features are not restored. Treat these issues.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

There are 118 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/ethernet/cadence/macb.h      |   7 ++
 drivers/net/ethernet/cadence/macb_main.c | 111 +++++++++++++++++++++++--------
 2 files changed, 91 insertions(+), 27 deletions(-)

diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index acc66a7..00ee5e8 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -1080,6 +1080,11 @@ struct macb_ptp_info {
             struct ifreq *ifr, int cmd);
 };

+struct macb_pm_data {
+   u32 scrt2;
+   u32 usrio;
+};
+
 struct macb_config {
    u32         caps;
    unsigned int        dma_burst_length;
@@ -1220,6 +1225,8 @@ struct macb {
    int tx_bd_rd_prefetch;

    u32 rx_intr_mask;
+
+   struct macb_pm_data pm_data;
 };

 #ifdef CONFIG_MACB_USE_HWSTAMP
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index bebd9b1..f825e39 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2849,10 +2849,14 @@ static int macb_get_ts_info(struct net_device *netdev,

 static void gem_enable_flow_filters(struct macb *bp, bool enable)
 {
+   struct net_device *netdev = bp->dev;
    struct ethtool_rx_fs_item *item;
    u32 t2_scr;
    int num_t2_scr;

+   if (!(netdev->features & NETIF_F_NTUPLE))
+       return;
+
    num_t2_scr = GEM_BFEXT(T2SCR, gem_readl(bp, DCFG8));

    list_for_each_entry(item, &bp->rx_fs_list.list, list) {
@@ -3012,8 +3016,7 @@ static int gem_add_flow_filter(struct net_device *netdev,
    gem_prog_cmp_regs(bp, fs);
    bp->rx_fs_list.count++;
    /* enable filtering if NTUPLE on */
-   if (netdev->features & NETIF_F_NTUPLE)
-       gem_enable_flow_filters(bp, 1);
+   gem_enable_flow_filters(bp, 1);

    spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
    return 0;
@@ -3201,6 +3204,50 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
    }
 }

+static inline void macb_set_txcsum_feature(struct macb *bp,
+                      netdev_features_t features)
+{
+   u32 val;
+
+   if (!macb_is_gem(bp))
+       return;
+
+   val = gem_readl(bp, DMACFG);
+   if (features & NETIF_F_HW_CSUM)
+       val |= GEM_BIT(TXCOEN);
+   else
+       val &= ~GEM_BIT(TXCOEN);
+
+   gem_writel(bp, DMACFG, val);
+}
+
+static inline void macb_set_rxcsum_feature(struct macb *bp,
+                      netdev_features_t features)
+{
+   struct net_device *netdev = bp->dev;
+   u32 val;
+
+   if (!macb_is_gem(bp))
+       return;
+
+   val = gem_readl(bp, NCFGR);
+   if ((features & NETIF_F_RXCSUM) && !(netdev->flags & IFF_PROMISC))
+       val |= GEM_BIT(RXCOEN);
+   else
+       val &= ~GEM_BIT(RXCOEN);
+
+   gem_writel(bp, NCFGR, val);
+}
+
+static inline void macb_set_rxflow_feature(struct macb *bp,
+                      netdev_features_t features)
+{
+   if (!macb_is_gem(bp))
+       return;
+
+   gem_enable_flow_filters(bp, !!(features & NETIF_F_NTUPLE));
+}
+
 static int macb_set_features(struct net_device *netdev,
                 netdev_features_t features)
 {
@@ -3208,39 +3255,35 @@ static int macb_set_features(struct net_device *netdev,
    netdev_features_t changed = features ^ netdev->features;

    /* TX checksum offload */
-   if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) {
-       u32 dmacfg;
-
-       dmacfg = gem_readl(bp, DMACFG);
-       if (features & NETIF_F_HW_CSUM)
-           dmacfg |= GEM_BIT(TXCOEN);
-       else
-           dmacfg &= ~GEM_BIT(TXCOEN);
-       gem_writel(bp, DMACFG, dmacfg);
-   }
+   if (changed & NETIF_F_HW_CSUM)
+       macb_set_txcsum_feature(bp, features);

    /* RX checksum offload */
-   if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) {
-       u32 netcfg;
-
-       netcfg = gem_readl(bp, NCFGR);
-       if (features & NETIF_F_RXCSUM &&
-           !(netdev->flags & IFF_PROMISC))
-           netcfg |= GEM_BIT(RXCOEN);
-       else
-           netcfg &= ~GEM_BIT(RXCOEN);
-       gem_writel(bp, NCFGR, netcfg);
-   }
+   if (changed & NETIF_F_RXCSUM)
+       macb_set_rxcsum_feature(bp, features);

    /* RX Flow Filters */
-   if ((changed & NETIF_F_NTUPLE) && macb_is_gem(bp)) {
-       bool turn_on = features & NETIF_F_NTUPLE;
+   if (changed & NETIF_F_NTUPLE)
+       macb_set_rxflow_feature(bp, features);

-       gem_enable_flow_filters(bp, turn_on);
-   }
    return 0;
 }

+static void macb_restore_features(struct macb *bp)
+{
+   struct net_device *netdev = bp->dev;
+   netdev_features_t features = netdev->features;
+
+   /* TX checksum offload */
+   macb_set_txcsum_feature(bp, features);
+
+   /* RX checksum offload */
+   macb_set_rxcsum_feature(bp, features);
+
+   /* RX Flow Filters */
+   macb_set_rxflow_feature(bp, features);
+}
+
 static const struct net_device_ops macb_netdev_ops = {
    .ndo_open       = macb_open,
    .ndo_stop       = macb_close,
@@ -4273,6 +4316,12 @@ static int __maybe_unused macb_suspend(struct device *dev)
        spin_lock_irqsave(&bp->lock, flags);
        macb_reset_hw(bp);
        spin_unlock_irqrestore(&bp->lock, flags);
+
+       if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
+           bp->pm_data.usrio = macb_or_gem_readl(bp, USRIO);
+
+       if (netdev->hw_features & NETIF_F_NTUPLE)
+           bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);
    }

    netif_carrier_off(netdev);
@@ -4301,6 +4350,13 @@ static int __maybe_unused macb_resume(struct device *dev)
        disable_irq_wake(bp->queues[0].irq);
    } 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);
+
+       if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
+           macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio);
+
        for (q = 0, queue = bp->queues; q < bp->num_queues;
             ++q, ++queue)
            napi_enable(&queue->napi);
@@ -4312,6 +4368,7 @@ static int __maybe_unused macb_resume(struct device *dev)
    bp->macbgem_ops.mog_init_rings(bp);
    macb_init_hw(bp);
    macb_set_rx_mode(netdev);
+   macb_restore_features(bp);
    netif_device_attach(netdev);
    if (bp->ptp_info)
        bp->ptp_info->ptp_init(netdev);

Leave a Reply

Your email address will not be published. Required fields are marked *