Added Wake on LAN

This commit is contained in:
Aditya Prayoga 2019-02-27 14:28:15 +08:00
parent 3eb8494c5e
commit c751e1d121
5 changed files with 261 additions and 0 deletions

View file

@ -0,0 +1,23 @@
diff --git a/arch/arm/boot/dts/armada-388-helios4.dts b/arch/arm/boot/dts/armada-388-helios4.dts
index 705adfa8c..d5afbfc53 100644
--- a/arch/arm/boot/dts/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/armada-388-helios4.dts
@@ -84,6 +84,18 @@
};
};
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&microsom_phy0_int_pins>;
+
+ wol {
+ label = "Wake-On-LAN";
+ linux,code = <KEY_WAKEUP>;
+ gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
+ wakeup-source;
+ };
+ };
+
io-leds {
compatible = "gpio-leds";
sata1-led {

View file

@ -0,0 +1,90 @@
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 661c5a38f..a25d61d54 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -38,6 +38,7 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
@@ -133,7 +134,7 @@ struct mvebu_gpio_chip {
struct regmap *regs;
u32 offset;
struct regmap *percpu_regs;
- int irqbase;
+ int bank_irq[4];
struct irq_domain *domain;
int soc_variant;
@@ -608,6 +609,33 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+/*
+ * Set interrupt number "irq" in the GPIO as a wake-up source.
+ * While system is running, all registered GPIO interrupts need to have
+ * wake-up enabled. When system is suspended, only selected GPIO interrupts
+ * need to have wake-up enabled.
+ * @param irq interrupt source number
+ * @param enable enable as wake-up if equal to non-zero
+ * @return This function returns 0 on success.
+ */
+static int mvebu_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct mvebu_gpio_chip *mvchip = gc->private;
+ int irq;
+ int bank;
+
+ bank = d->hwirq % 8;
+ irq = mvchip->bank_irq[bank];
+
+ if (enable)
+ enable_irq_wake(irq);
+ else
+ disable_irq_wake(irq);
+
+ return 0;
+}
+
/*
* Functions implementing the pwm_chip methods
*/
@@ -1277,7 +1305,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
err = irq_alloc_domain_generic_chips(
mvchip->domain, ngpios, 2, np->name, handle_level_irq,
- IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, IRQ_GC_INIT_NESTED_LOCK);
if (err) {
dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
mvchip->chip.label);
@@ -1295,6 +1323,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ct->chip.name = mvchip->chip.label;
ct = &gc->chip_types[1];
@@ -1303,6 +1333,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;
@@ -1318,6 +1350,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
continue;
irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
mvchip);
+ mvchip->bank_irq[i] = irq;
}
/* Some MVEBU SoCs have simple PWM support for GPIO lines */

BIN
docs/img/wol/schematic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

147
docs/wol.md Normal file
View file

@ -0,0 +1,147 @@
![Ethernet PHY](/img/wol/schematic.png)
The ARMADA 388 provides several waking options sourced by different peripherals to take the system out of power save modes. Some of the options are
* Wake on GPIO
* Wake on LAN
Currently Helios4 use PHY interrupt and Wake on GPIO event to implement Wake on LAN.
## Device Tree Support
Linux provides gpio-keys driver to handle GPIO event and can be configured as wakeup source.
```
gpio-keys {
compatible = "gpio-keys";
pinctrl-0 = <&microsom_phy0_int_pins>;
wol {
label = "Wake-On-LAN";
linux,code = <KEY_WAKEUP>;
gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
wakeup-source;
};
};
```
Device Tree Patch can be found [here](/files/wol/helios4-dts-add-wake-on-lan-support.patch)
## Kernel Patch
Current gpio-mvebu driver does not implement [irq_set_wake()](https://www.kernel.org/doc/html/v4.14/core-api/genericirq.html?highlight=irq_set_wake#c.irq_chip)
to support GPIO as wakeup source and properly route it to upper interrupt controller (Arm GIC).
This will raise following issues:
- System unable to wake up from Suspend-to-RAM
- Kernel crash during wakeup from standby
```
[ 59.169436] ------------[ cut here ]------------
[ 59.174075] WARNING: CPU: 0 PID: 1535 at kernel/irq/manage.c:623 irq_set_irq_wake+0xe4/0x11c
[ 59.182533] Unbalanced IRQ 50 wake disable
[ 59.186638] Modules linked in: lz4hc lz4hc_compress marvell_cesa zram zsmalloc lm75 pwm_fan ip_tables x_tables
[ 59.196690] CPU: 0 PID: 1535 Comm: bash Not tainted 4.14.94-mvebu+ #14
[ 59.203234] Hardware name: Marvell Armada 380/385 (Device Tree)
[ 59.209183] [<c01118d0>] (unwind_backtrace) from [<c010c7cc>] (show_stack+0x10/0x14)
[ 59.216955] [<c010c7cc>] (show_stack) from [<c095091c>] (dump_stack+0x88/0x9c)
[ 59.224204] [<c095091c>] (dump_stack) from [<c012ab9c>] (__warn+0xe8/0x100)
[ 59.231188] [<c012ab9c>] (__warn) from [<c012abfc>] (warn_slowpath_fmt+0x48/0x6c)
[ 59.238696] [<c012abfc>] (warn_slowpath_fmt) from [<c017bb64>] (irq_set_irq_wake+0xe4/0x11c)
[ 59.247160] [<c017bb64>] (irq_set_irq_wake) from [<c0747594>] (gpio_keys_resume+0xb0/0x11c)
[ 59.255537] [<c0747594>] (gpio_keys_resume) from [<c0654b34>] (dpm_run_callback+0x54/0xec)
[ 59.263826] [<c0654b34>] (dpm_run_callback) from [<c0655180>] (device_resume+0xcc/0x270)
[ 59.271941] [<c0655180>] (device_resume) from [<c0656660>] (dpm_resume+0x100/0x230)
[ 59.279621] [<c0656660>] (dpm_resume) from [<c06569e4>] (dpm_resume_end+0xc/0x18)
[ 59.287128] [<c06569e4>] (dpm_resume_end) from [<c0175af8>] (suspend_devices_and_enter+0x210/0x5e0)
[ 59.296202] [<c0175af8>] (suspend_devices_and_enter) from [<c01761c0>] (pm_suspend+0x2f8/0x380)
[ 59.304927] [<c01761c0>] (pm_suspend) from [<c0174a30>] (state_store+0x70/0xcc)
[ 59.312260] [<c0174a30>] (state_store) from [<c02c80e4>] (kernfs_fop_write+0xe8/0x1c4)
[ 59.320204] [<c02c80e4>] (kernfs_fop_write) from [<c024ce78>] (vfs_write+0xa4/0x1b4)
[ 59.327972] [<c024ce78>] (vfs_write) from [<c024d0b4>] (SyS_write+0x4c/0xac)
[ 59.335045] [<c024d0b4>] (SyS_write) from [<c0108620>] (ret_fast_syscall+0x0/0x54)
[ 59.342633] ---[ end trace c725de247edb5ce9 ]---
[ 59.474369] ata2: SATA link down (SStatus 0 SControl 300)
[ 59.474443] ata3: SATA link down (SStatus 0 SControl 300)
[ 59.638619] ata1: SATA link down (SStatus 0 SControl 300)
[ 59.647170] ata4: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[ 60.081905] ata1: SATA link down (SStatus 0 SControl 300)
[ 60.087343] ata1: limiting SATA link speed to 1.5 Gbps
[ 60.386518] mvneta f1070000.ethernet eth0: Link is Down
[ 60.578411] ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
[ 61.162892] ata4.00: configured for UDMA/100
[ 62.431232] mvneta f1070000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
[ 63.087435] ata1.00: configured for UDMA/100
[ 63.159889] OOM killer enabled.
[ 63.164643] Restarting tasks ... done.
[ 63.181059] PM: suspend exit
```
- System can wake up from any GPIO interrupt without need to define as wakeup source
To fix the issue, gpio-mvebu driver needs to be patched to implement [irq_set_wake()](https://www.kernel.org/doc/html/v4.14/core-api/genericirq.html?highlight=irq_set_wake#c.irq_chip)
and only enable interrupt on GPIO defined as wakeup source.
Patch for Linux Kernel 4.14.x can be found [here](/files/wol/lk4.14-mvebu-gpio-add_wake_on_gpio_support.patch)
## Enabling WoL
Enable the PHY to only raise interrupt when magic packet received then enter suspend mode with these commands:
```
sudo ethtool -s eth0 wol g
sudo systemctl suspend
```
Both command has to be executed to enter suspend mode otherwise there is a risk that Helios4 will not wake up on magic packet received event.
More explaination regarding this issue on next section.
## Limitation with Current Approach
PHY INT pin supposed to be handled by the Ethernet controller so when there is an interrupt the driver can respond and acknowledge the interrupt.
Without this acknowledgement, the PHY INT pin will stay active and the PHY will not trigger another interrupt.
On specific case that after user enabled the wol and magic packet received before entering suspend mode, Helios4 will not able to wake up.
The reason is PHY interrupt already triggered before entering suspend mode and no other interrupt triggered during suspend mode.
The Ethernet controller driver will reset PHY interrupt during resume and when enabling wol.
Therefore it is advised to always set wol (**sudo ethtool -s eth0 wol g**) before entering suspend.
## Power Consumption
Measured using Sonoff POW R2 on AC side
| Power state | Power (Watt) | Current (Ampere) | Remarks |
|---------------|---------------|------------------|---------|
| Idle | 16.18 - 19.87 | 0.14 - 0.17 | |
| Standby | 8.24 - 8.63 | 0.09 - 0.10 | |
| Suspend | 7.46 - 7.71 | 0.07 - 0.08 | |
| Halt/Shutdown | 11.95 | 0.11 | HDDs still active, fans run on full speed |
!!! note
* Nominal Input Voltage: 220V
* HDD: 4x WD Red 2TB (WD20EFRX)
* [I2C OLED screen](/i2c/) attached to the systems
* Variation of power consumption sometimes due to fluctutation of the input voltage
## Thermal Issue
Using [Batch 2 fan](/pwm/#new-fan-batch-2)
| Power state | Temperature (°C) | Remarks |
|---------------|------------------|---------|
| Standby | 89 - 90 | Fan stopped |
| Suspend | 81 - 87 | Fan stopped |
Using [Batch 1 fan](/pwm/#old-fan-batch-1)
| Power state | Temperature (°C) | Remarks |
|---------------|------------------|---------|
| Standby | - | Not yet tested |
| Suspend | 74 -76 | Fan run in minimum speed |

View file

@ -75,6 +75,7 @@ pages:
- PWM (Fan) : 'pwm.md'
- SDIO (SD Card) : 'sdcard.md'
- SPI (NOR Flash) : 'spi.md'
- Wake-On-LAN : 'wol.md'
- Development:
- Armbian : 'armbian.md'
- FreeBSD : 'freebsd.md'