summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/cadence/macb_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/cadence/macb_main.c')
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c221
1 files changed, 176 insertions, 45 deletions
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 2213e6ab8151..6761f404b8aa 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -578,7 +578,7 @@ static void macb_mac_config(struct phylink_config *config, unsigned int mode,
if (bp->caps & MACB_CAPS_MACB_IS_EMAC) {
if (state->interface == PHY_INTERFACE_MODE_RMII)
ctrl |= MACB_BIT(RM9200_RMII);
- } else {
+ } else if (macb_is_gem(bp)) {
ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));
if (state->interface == PHY_INTERFACE_MODE_SGMII)
@@ -639,10 +639,13 @@ static void macb_mac_link_up(struct phylink_config *config,
ctrl |= MACB_BIT(FD);
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
- ctrl &= ~(GEM_BIT(GBE) | MACB_BIT(PAE));
+ ctrl &= ~MACB_BIT(PAE);
+ if (macb_is_gem(bp)) {
+ ctrl &= ~GEM_BIT(GBE);
- if (speed == SPEED_1000)
- ctrl |= GEM_BIT(GBE);
+ if (speed == SPEED_1000)
+ ctrl |= GEM_BIT(GBE);
+ }
/* We do not support MLO_PAUSE_RX yet */
if (tx_pause)
@@ -1467,7 +1470,7 @@ static void macb_hresp_error_task(unsigned long data)
{
struct macb *bp = (struct macb *)data;
struct net_device *dev = bp->dev;
- struct macb_queue *queue = bp->queues;
+ struct macb_queue *queue;
unsigned int q;
u32 ctrl;
@@ -1517,6 +1520,64 @@ static void macb_tx_restart(struct macb_queue *queue)
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
}
+static irqreturn_t macb_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 & MACB_BIT(WOL)) {
+ queue_writel(queue, IDR, MACB_BIT(WOL));
+ macb_writel(bp, WOL, 0);
+ netdev_vdbg(bp->dev, "MACB 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, MACB_BIT(WOL));
+ pm_wakeup_event(&bp->pdev->dev, 0);
+ }
+
+ spin_unlock(&bp->lock);
+
+ return IRQ_HANDLED;
+}
+
+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));
+ pm_wakeup_event(&bp->pdev->dev, 0);
+ }
+
+ spin_unlock(&bp->lock);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t macb_interrupt(int irq, void *dev_id)
{
struct macb_queue *queue = dev_id;
@@ -1933,7 +1994,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
unsigned int desc_cnt, nr_frags, frag_size, f;
unsigned int hdrlen;
- bool is_lso, is_udp = 0;
+ bool is_lso;
netdev_tx_t ret = NETDEV_TX_OK;
if (macb_clear_csum(skb)) {
@@ -1949,10 +2010,8 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
is_lso = (skb_shinfo(skb)->gso_size != 0);
if (is_lso) {
- is_udp = !!(ip_hdr(skb)->protocol == IPPROTO_UDP);
-
/* length of headers */
- if (is_udp)
+ if (ip_hdr(skb)->protocol == IPPROTO_UDP)
/* only queue eth + ip headers separately for UDP */
hdrlen = skb_transport_offset(skb);
else
@@ -3318,6 +3377,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,
@@ -3488,8 +3549,6 @@ static void macb_probe_queues(void __iomem *mem,
unsigned int *queue_mask,
unsigned int *num_queues)
{
- unsigned int hw_q;
-
*queue_mask = 0x1;
*num_queues = 1;
@@ -3503,13 +3562,8 @@ static void macb_probe_queues(void __iomem *mem,
return;
/* bit 0 is never set but queue 0 always exists */
- *queue_mask = readl_relaxed(mem + GEM_DCFG6) & 0xff;
-
- *queue_mask |= 0x1;
-
- for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q)
- if (*queue_mask & (1 << hw_q))
- (*num_queues)++;
+ *queue_mask |= readl_relaxed(mem + GEM_DCFG6) & 0xff;
+ *num_queues = hweight32(*queue_mask);
}
static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
@@ -4576,33 +4630,77 @@ 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);
+ ++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
+ */
+ devm_free_irq(dev, bp->queues[0].irq, bp->queues);
+ if (macb_is_gem(bp)) {
+ 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);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ return err;
+ }
+ queue_writel(bp->queues, IER, GEM_BIT(WOL));
+ gem_writel(bp, WOL, MACB_BIT(MAG));
+ } else {
+ err = devm_request_irq(dev, bp->queues[0].irq, macb_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);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ return err;
+ }
+ 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)) {
rtnl_lock();
phylink_stop(bp->phylink);
rtnl_unlock();
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 (!(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);
- }
+ if (netdev->hw_features & NETIF_F_NTUPLE)
+ bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);
if (bp->ptp_info)
bp->ptp_info->ptp_remove(netdev);
@@ -4617,7 +4715,9 @@ 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;
@@ -4626,29 +4726,60 @@ static int __maybe_unused macb_resume(struct device *dev)
pm_runtime_force_resume(dev);
if (bp->wol & MACB_WOL_ENABLED) {
- macb_writel(bp, IDR, MACB_BIT(WOL));
- macb_writel(bp, WOL, 0);
- 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);
+ 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);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ return err;
+ }
+ spin_unlock_irqrestore(&bp->lock, flags);
- if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
- macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio);
+ disable_irq_wake(bp->queues[0].irq);
- for (q = 0, queue = bp->queues; q < bp->num_queues;
- ++q, ++queue)
- napi_enable(&queue->napi);
+ /* Now make sure we disable phy before moving
+ * to common restore path
+ */
rtnl_lock();
- phylink_start(bp->phylink);
+ phylink_stop(bp->phylink);
rtnl_unlock();
}
+ for (q = 0, queue = bp->queues; q < bp->num_queues;
+ ++q, ++queue)
+ napi_enable(&queue->napi);
+
+ 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);
+
+ macb_writel(bp, NCR, MACB_BIT(MPE));
macb_init_hw(bp);
macb_set_rx_mode(netdev);
macb_restore_features(bp);
+ rtnl_lock();
+ phylink_start(bp->phylink);
+ rtnl_unlock();
+
netif_device_attach(netdev);
if (bp->ptp_info)
bp->ptp_info->ptp_init(netdev);