{"id":592,"date":"2026-10-19T14:26:53","date_gmt":"2026-10-19T13:26:53","guid":{"rendered":"https:\/\/www.fabidouille.com\/?p=592"},"modified":"2026-10-19T14:26:53","modified_gmt":"2026-10-19T13:26:53","slug":"renassance-wol","status":"publish","type":"post","link":"https:\/\/www.fabidouille.com\/?p=592","title":{"rendered":"ReNASsance UPDATE: it wakes up"},"content":{"rendered":"<pre class=\"wp-block-code\"><code>orion-mdio: RN102 WOL readback bmcr=0x0 mask=0x80 ctrl=0x4580 tcr=0x4985\nreboot: Power down<\/code><\/pre>\n<p>For weeks, these two lines ended every Wake-on-LAN test on my ReadyNAS RN102. Then nothing. No LED, no ping, no wake.<\/p>\n<p>In the first [ReNASsance](https:\/\/fabidouille.com\/?p=504) post I wrote \u00ab\u00a0Wake-on-LAN after power-off: still not working\u00a0\u00bb. In my public guide I went further: a hardware limit, the board cuts the power of the network chip, impossible. I wrote that with a lot of confidence.<\/p>\n<p>It was wrong. The fix is one line.<\/p>\n<h2 class=\"wp-block-heading\">Why it mattered<\/h2>\n<p>The NAS has two disks in RAID1, and the Debian system lives on the same disks. So when the box is on, something always ends up waking the disks. The old disk has 24,705 hours and about 40,800 start\/stop cycles. The best thing for it: no power at all when nobody uses the NAS. But without WOL, \u00ab\u00a0off\u00a0\u00bb means \u00ab\u00a0off until someone walks to the box\u00a0\u00bb.<\/p>\n<p>Running, with the disks spinning, the box takes 21.7 W at the wall.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.fabidouille.com\/wp-content\/uploads\/2026\/10\/meter-on.jpg\" alt=\"Voltcraft Energy Logger 4000F plug meter showing 21.7 W, 42.7 VA and power factor 0.50\"\/><figcaption>NAS on: 21.7 W (top line). The 0.50 at the bottom is the power factor, not watts.<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">The stock kernel woke up<\/h2>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.fabidouille.com\/wp-content\/uploads\/2026\/10\/bench.jpg\" alt=\"The RN102 on a wooden desk, its 12 V power brick plugged into a Voltcraft plug meter, a yellow Ethernet cable and the serial wires at the back\"\/><figcaption>The test bench: plug meter, power brick, NAS, and the serial wires that stay plugged in.<\/figcaption><\/figure>\n<p>First test: boot the old Netgear kernel (4.4) from RAM over TFTP, with a tiny init that touches no disk, sets <code>ethtool -s eth0 wol g<\/code> and powers off. My plug meter said 0.5 W. With my Debian kernel, same test: 0.2 W.<\/p>\n<p>Then ten magic packets. The NAS started.<\/p>\n<p>Same board, same power supply. So not a hardware limit. Something in my kernel leaves the network chip (a Marvell 88E1318S \u00ab\u00a0PHY\u00a0\u00bb) in a different state.<\/p>\n<h2 class=\"wp-block-heading\">Wrong suspect<\/h2>\n<p>Netgear arms WOL in a function that runs at power-off, <code>orion_mdio_shutdown()<\/code>. My kernel has a copy of it. I decompiled both (Ghidra) and compared every register write. One value was different: an interrupt mask, <code>0x4985<\/code> at Netgear, <code>0x0080<\/code> in mine.<\/p>\n<p>So I patched one ARM instruction in my kernel, <code>mov r3,#0x80<\/code> became <code>movw r3,#0x4985<\/code>, booted it from RAM, powered off. 0.2 W. Ten packets. Nothing.<\/p>\n<p>Rat\u00e9.<\/p>\n<h2 class=\"wp-block-heading\">The line Netgear deleted<\/h2>\n<p>The next suspect was the PHY driver itself. In the Netgear kernel I found the driver table of the 88E1318S and disassembled its functions. The WOL function is exactly the upstream Linux 4.4 one. But in <code>m88e1121_config_aneg()<\/code>, one line of upstream is missing:<\/p>\n<pre class=\"wp-block-code\"><code>phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);  \/* page 3, reg 0x10 = 0x0030 *\/<\/code><\/pre>\n<p>It is not in the Netgear kernel. Linux 7.0 does the same write in another function, <code>marvell_config_led()<\/code>. It is the \u00ab\u00a0LED function\u00a0\u00bb register of the PHY. And a soft reset of the PHY does not clear it, so the value is still there at power-off.<\/p>\n<p>Why would LEDs matter for WOL? Because this PHY has a pin called LED[2], and Netgear&rsquo;s power-off code turns it into an interrupt line (\u00ab\u00a0INTn\u00a0\u00bb) for the magic packet. On this board it must go to the power circuit. I have no schematic, so that part is a guess, but a good one.<\/p>\n<h2 class=\"wp-block-heading\">What U-Boot says<\/h2>\n<p>What value does Netgear keep, if it never writes it? The one U-Boot leaves. So: serial cable, catch the U-Boot prompt, and read the register. This old Marvell U-Boot has no <code>mii<\/code> command, but it has <code>phyRead<\/code>\/<code>phyWrite<\/code>, all numbers in hex:<\/p>\n<pre class=\"wp-block-code\"><code>Marvell&gt;&gt; phyWrite 0 16 3     # page 3\nMarvell&gt;&gt; phyRead 0 10        # register 0x10\n0x83f\nMarvell&gt;&gt; phyWrite 0 16 0     # back to page 0<\/code><\/pre>\n<p><code>0x083f<\/code> against <code>0x0030<\/code>. Each LED has 4 bits. For LED[2]: <code>0x8<\/code> at U-Boot (\u00ab\u00a0forced off\u00a0\u00bb), <code>0x0<\/code> in Debian (\u00ab\u00a0on when link is up\u00a0\u00bb). My kernel turns the wake wire into a link LED.<\/p>\n<h2 class=\"wp-block-heading\">Two tests, two wakes<\/h2>\n<p>To test it without building a kernel, I patched the first instruction of <code>marvell_config_led()<\/code> to <code>bx lr<\/code> (return at once), and booted that from RAM. Meter: 0.5 W. Magic packets at 11:05:47, and the serial console printed <code>BootROM 1.08<\/code> at 11:05:48. Again later: same result.<\/p>\n<p>The clean fix needs no patch at all. The Marvell driver can set any PHY register from the device tree, after its LED default:<\/p>\n<pre class=\"wp-block-code\"><code>ethernet-phy@0 {\n\treg = &lt;0&gt;;\n\tmarvell,reg-init = &lt;3 0x10 0 0x083f&gt;;  \/* page 3, reg 0x10, U-Boot value *\/\n};<\/code><\/pre>\n<p>On this NAS the device tree is glued to the end of the kernel image in NAND. So: same kernel, new device tree, rebuilt with the same <code>mkimage<\/code> command. First a RAM boot of that exact image and a real Debian <code>poweroff<\/code>: it woke. Then a backup of the NAND partition, the flash, a full read-back, a reboot. Final test, normal <code>poweroff<\/code>, packets at 14:13:20: the NAS started in the same second, Debian answered ping 82 s later.<\/p>\n<p>Ouf.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.fabidouille.com\/wp-content\/uploads\/2026\/10\/off-bench.jpg\" alt=\"The RN102 switched off on the desk, next to the Voltcraft plug meter\"\/><figcaption>NAS off, WOL armed, fixed Debian kernel.<\/figcaption><\/figure>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.fabidouille.com\/wp-content\/uploads\/2026\/10\/meter-05w.jpg\" alt=\"Voltcraft Energy Logger 4000F showing 0.5 W, 3.5 VA and power factor 0.16\"\/><figcaption>0.5 W at the wall: the network chip is awake and listening. Without the fix it was 0.2 W.<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Now the NAS sleeps for real<\/h2>\n<ul class=\"wp-block-list\">\n<li>before: always on, disks parked after 5 minutes when nothing happens<\/li>\n<li>after: off after 30 minutes without activity, woken when needed<\/li>\n<\/ul>\n<p>The home server watches the NAS&rsquo;s own activity (disk I\/O, NFS and Samba traffic, a running btrfs scrub). It powers it off when there is nothing, and wakes it with WOL when a download is finished, for the weekly backup, and before the monthly scrub. The \u00ab\u00a0NAS\u00a0\u00bb button in my home automation app works both ways again. (The \u00ab\u00a0Off\u00a0\u00bb side had been broken for a while: its SSH key file had the wrong permissions, and OpenSSH ignores a private key that others can read. Nobody noticed, because nothing could switch it on anyway.)<\/p>\n<p>The guide on GitHub is corrected, with the patch and the steps for an installed NAS: github.com\/fabien0008\/readynas-debian-migration (doc 12). If you have an RN104 or RN2120 that does not wake, read that register at your U-Boot prompt. I would like to know your value.<\/p>\n<h2 class=\"wp-block-heading\">How AI was used<\/h2>\n<p>AI coding agents (Claude Code) did most of the hands-on work from my home server: decompiling both kernels, comparing the register writes, driving U-Boot over the serial cable, building the test images, the flash with its backup and read-back, and the new sleep and wake scripts. My part: refuse the \u00ab\u00a0hardware limit\u00a0\u00bb conclusion after the stock kernel woke, press the front button and read the plug meter at each test, decide each step that could break something (flash, firewall, reboots), and choose \u00ab\u00a0off when idle\u00a0\u00bb over \u00ab\u00a0always on\u00a0\u00bb.<\/p>\n<p>Note: I don&rsquo;t have much time for the blog these days, so this post was written with the help of an AI, from my own notes, then read and corrected by me. Better to share the content this way than not at all.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wake-on-LAN on the RN102 was \u00ab\u00a0a hardware limit\u00a0\u00bb. It was one PHY register: the Linux driver turns the wake pin into a link LED. One device-tree line, and the NAS now sleeps for real.<\/p>\n","protected":false},"author":0,"featured_media":591,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-592","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-non-classe"],"_links":{"self":[{"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=\/wp\/v2\/posts\/592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=592"}],"version-history":[{"count":0,"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=\/wp\/v2\/posts\/592\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=\/wp\/v2\/media\/591"}],"wp:attachment":[{"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fabidouille.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}