net: macb: save/restore the remaining registers and features
authorClaudiu Beznea <claudiu.beznea@microchip.com>
Wed, 22 May 2019 08:24:43 +0000 (08:24 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 May 2019 00:21:21 +0000 (17:21 -0700)
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>
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cadence/macb_main.c

index acc66a7e7b95e5af618a7fef300957ca3edf2207..00ee5e8e0ff0ff018618342b26af1c972ae49e9c 100644 (file)
@@ -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
index bebd9b1aeb6473e696207fbe22f1e25dc63bc378..f825e39605403af0b167ff09404a64e697e06d49 100644 (file)
@@ -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);