Skip to content

Commit 558e35c

Browse files
noglitchdavem330
authored andcommitted
net: macb: WoL support for GEM type of Ethernet controller
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 <harinik@xilinx.com>, thanks! Cc: Claudiu Beznea <claudiu.beznea@microchip.com> Cc: Harini Katakam <harini.katakam@xilinx.com> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a8b7b2d commit 558e35c

2 files changed

Lines changed: 129 additions & 27 deletions

File tree

‎drivers/net/ethernet/cadence/macb.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
#define GEM_SA3T 0x009C /* Specific3 Top */
9191
#define GEM_SA4B 0x00A0 /* Specific4 Bottom */
9292
#define GEM_SA4T 0x00A4 /* Specific4 Top */
93+
#define GEM_WOL 0x00b8 /* Wake on LAN */
9394
#define GEM_EFTSH 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */
9495
#define GEM_EFRSH 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */
9596
#define GEM_PEFTSH 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */
@@ -396,6 +397,8 @@
396397
#define MACB_PDRSFT_SIZE 1
397398
#define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */
398399
#define MACB_SRI_SIZE 1
400+
#define GEM_WOL_OFFSET 28 /* Enable wake-on-lan interrupt */
401+
#define GEM_WOL_SIZE 1
399402

400403
/* Timer increment fields */
401404
#define MACB_TI_CNS_OFFSET 0

‎drivers/net/ethernet/cadence/macb_main.c‎

Lines changed: 126 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,35 @@ static void macb_tx_restart(struct macb_queue *queue)
15171517
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
15181518
}
15191519

1520+
static irqreturn_t gem_wol_interrupt(int irq, void *dev_id)
1521+
{
1522+
struct macb_queue *queue = dev_id;
1523+
struct macb *bp = queue->bp;
1524+
u32 status;
1525+
1526+
status = queue_readl(queue, ISR);
1527+
1528+
if (unlikely(!status))
1529+
return IRQ_NONE;
1530+
1531+
spin_lock(&bp->lock);
1532+
1533+
if (status & GEM_BIT(WOL)) {
1534+
queue_writel(queue, IDR, GEM_BIT(WOL));
1535+
gem_writel(bp, WOL, 0);
1536+
netdev_vdbg(bp->dev, "GEM WoL: queue = %u, isr = 0x%08lx\n",
1537+
(unsigned int)(queue - bp->queues),
1538+
(unsigned long)status);
1539+
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
1540+
queue_writel(queue, ISR, GEM_BIT(WOL));
1541+
pm_wakeup_event(&bp->pdev->dev, 0);
1542+
}
1543+
1544+
spin_unlock(&bp->lock);
1545+
1546+
return IRQ_HANDLED;
1547+
}
1548+
15201549
static irqreturn_t macb_interrupt(int irq, void *dev_id)
15211550
{
15221551
struct macb_queue *queue = dev_id;
@@ -3316,6 +3345,8 @@ static const struct ethtool_ops macb_ethtool_ops = {
33163345
static const struct ethtool_ops gem_ethtool_ops = {
33173346
.get_regs_len = macb_get_regs_len,
33183347
.get_regs = macb_get_regs,
3348+
.get_wol = macb_get_wol,
3349+
.set_wol = macb_set_wol,
33193350
.get_link = ethtool_op_get_link,
33203351
.get_ts_info = macb_get_ts_info,
33213352
.get_ethtool_stats = gem_get_ethtool_stats,
@@ -4567,33 +4598,68 @@ static int __maybe_unused macb_suspend(struct device *dev)
45674598
struct macb_queue *queue = bp->queues;
45684599
unsigned long flags;
45694600
unsigned int q;
4601+
int err;
45704602

45714603
if (!netif_running(netdev))
45724604
return 0;
45734605

45744606
if (bp->wol & MACB_WOL_ENABLED) {
4575-
macb_writel(bp, IER, MACB_BIT(WOL));
4576-
macb_writel(bp, WOL, MACB_BIT(MAG));
4577-
enable_irq_wake(bp->queues[0].irq);
4578-
netif_device_detach(netdev);
4579-
} else {
4580-
netif_device_detach(netdev);
4607+
spin_lock_irqsave(&bp->lock, flags);
4608+
/* Flush all status bits */
4609+
macb_writel(bp, TSR, -1);
4610+
macb_writel(bp, RSR, -1);
45814611
for (q = 0, queue = bp->queues; q < bp->num_queues;
4582-
++q, ++queue)
4583-
napi_disable(&queue->napi);
4612+
++q, ++queue) {
4613+
/* Disable all interrupts */
4614+
queue_writel(queue, IDR, -1);
4615+
queue_readl(queue, ISR);
4616+
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
4617+
queue_writel(queue, ISR, -1);
4618+
}
4619+
/* Change interrupt handler and
4620+
* Enable WoL IRQ on queue 0
4621+
*/
4622+
if (macb_is_gem(bp)) {
4623+
devm_free_irq(dev, bp->queues[0].irq, bp->queues);
4624+
err = devm_request_irq(dev, bp->queues[0].irq, gem_wol_interrupt,
4625+
IRQF_SHARED, netdev->name, bp->queues);
4626+
if (err) {
4627+
dev_err(dev,
4628+
"Unable to request IRQ %d (error %d)\n",
4629+
bp->queues[0].irq, err);
4630+
spin_unlock_irqrestore(&bp->lock, flags);
4631+
return err;
4632+
}
4633+
queue_writel(bp->queues, IER, GEM_BIT(WOL));
4634+
gem_writel(bp, WOL, MACB_BIT(MAG));
4635+
} else {
4636+
queue_writel(bp->queues, IER, MACB_BIT(WOL));
4637+
macb_writel(bp, WOL, MACB_BIT(MAG));
4638+
}
4639+
spin_unlock_irqrestore(&bp->lock, flags);
4640+
4641+
enable_irq_wake(bp->queues[0].irq);
4642+
}
4643+
4644+
netif_device_detach(netdev);
4645+
for (q = 0, queue = bp->queues; q < bp->num_queues;
4646+
++q, ++queue)
4647+
napi_disable(&queue->napi);
4648+
4649+
if (!(bp->wol & MACB_WOL_ENABLED)) {
45844650
rtnl_lock();
45854651
phylink_stop(bp->phylink);
45864652
rtnl_unlock();
45874653
spin_lock_irqsave(&bp->lock, flags);
45884654
macb_reset_hw(bp);
45894655
spin_unlock_irqrestore(&bp->lock, flags);
4656+
}
45904657

4591-
if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
4592-
bp->pm_data.usrio = macb_or_gem_readl(bp, USRIO);
4658+
if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
4659+
bp->pm_data.usrio = macb_or_gem_readl(bp, USRIO);
45934660

4594-
if (netdev->hw_features & NETIF_F_NTUPLE)
4595-
bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);
4596-
}
4661+
if (netdev->hw_features & NETIF_F_NTUPLE)
4662+
bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);
45974663

45984664
if (bp->ptp_info)
45994665
bp->ptp_info->ptp_remove(netdev);
@@ -4608,7 +4674,9 @@ static int __maybe_unused macb_resume(struct device *dev)
46084674
struct net_device *netdev = dev_get_drvdata(dev);
46094675
struct macb *bp = netdev_priv(netdev);
46104676
struct macb_queue *queue = bp->queues;
4677+
unsigned long flags;
46114678
unsigned int q;
4679+
int err;
46124680

46134681
if (!netif_running(netdev))
46144682
return 0;
@@ -4617,29 +4685,60 @@ static int __maybe_unused macb_resume(struct device *dev)
46174685
pm_runtime_force_resume(dev);
46184686

46194687
if (bp->wol & MACB_WOL_ENABLED) {
4620-
macb_writel(bp, IDR, MACB_BIT(WOL));
4621-
macb_writel(bp, WOL, 0);
4622-
disable_irq_wake(bp->queues[0].irq);
4623-
} else {
4624-
macb_writel(bp, NCR, MACB_BIT(MPE));
4625-
4626-
if (netdev->hw_features & NETIF_F_NTUPLE)
4627-
gem_writel_n(bp, ETHT, SCRT2_ETHT, bp->pm_data.scrt2);
4688+
spin_lock_irqsave(&bp->lock, flags);
4689+
/* Disable WoL */
4690+
if (macb_is_gem(bp)) {
4691+
queue_writel(bp->queues, IDR, GEM_BIT(WOL));
4692+
gem_writel(bp, WOL, 0);
4693+
} else {
4694+
queue_writel(bp->queues, IDR, MACB_BIT(WOL));
4695+
macb_writel(bp, WOL, 0);
4696+
}
4697+
/* Clear ISR on queue 0 */
4698+
queue_readl(bp->queues, ISR);
4699+
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
4700+
queue_writel(bp->queues, ISR, -1);
4701+
/* Replace interrupt handler on queue 0 */
4702+
devm_free_irq(dev, bp->queues[0].irq, bp->queues);
4703+
err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
4704+
IRQF_SHARED, netdev->name, bp->queues);
4705+
if (err) {
4706+
dev_err(dev,
4707+
"Unable to request IRQ %d (error %d)\n",
4708+
bp->queues[0].irq, err);
4709+
spin_unlock_irqrestore(&bp->lock, flags);
4710+
return err;
4711+
}
4712+
spin_unlock_irqrestore(&bp->lock, flags);
46284713

4629-
if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
4630-
macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio);
4714+
disable_irq_wake(bp->queues[0].irq);
46314715

4632-
for (q = 0, queue = bp->queues; q < bp->num_queues;
4633-
++q, ++queue)
4634-
napi_enable(&queue->napi);
4716+
/* Now make sure we disable phy before moving
4717+
* to common restore path
4718+
*/
46354719
rtnl_lock();
4636-
phylink_start(bp->phylink);
4720+
phylink_stop(bp->phylink);
46374721
rtnl_unlock();
46384722
}
46394723

4724+
for (q = 0, queue = bp->queues; q < bp->num_queues;
4725+
++q, ++queue)
4726+
napi_enable(&queue->napi);
4727+
4728+
if (netdev->hw_features & NETIF_F_NTUPLE)
4729+
gem_writel_n(bp, ETHT, SCRT2_ETHT, bp->pm_data.scrt2);
4730+
4731+
if (!(bp->caps & MACB_CAPS_USRIO_DISABLED))
4732+
macb_or_gem_writel(bp, USRIO, bp->pm_data.usrio);
4733+
4734+
macb_writel(bp, NCR, MACB_BIT(MPE));
46404735
macb_init_hw(bp);
46414736
macb_set_rx_mode(netdev);
46424737
macb_restore_features(bp);
4738+
rtnl_lock();
4739+
phylink_start(bp->phylink);
4740+
rtnl_unlock();
4741+
46434742
netif_device_attach(netdev);
46444743
if (bp->ptp_info)
46454744
bp->ptp_info->ptp_init(netdev);

0 commit comments

Comments
 (0)