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>
This commit is contained in:
Claudiu Beznea 2019-05-22 08:24:43 +00:00 committed by David S. Miller
parent 8f073036bf
commit c1e85c6ce5
2 changed files with 91 additions and 27 deletions

View 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

View 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);