diary at Telent Netowrks

In the Nix of time#

Mon, 15 Jan 2018 18:35:04 +0000

[ I'm not sure I can keep up these puns in the blog post titles much longer. That may be welcome news for my readers, of course. ]

I was expecting this blog post to be along the lines of "there is no progress to report since last week but I am writing anyway just to maintain the weekly schedule", but happily, last night I saw the board boot with an ethernet driver and was even able to ping it.

<6>libphy: ag71xx_mdio: probed
<6>ag71xx-mdio.1: Found an AR7240/AR9330 built-in switch
<6>eth0: Atheros AG71xx at 0xba000000, irq 5, mode:GMII
<6>ag71xx ag71xx.0: connected to PHY at ag71xx-mdio.1:04 [uid=004dd041, driver=]
<6>eth1: Atheros AG71xx at 0xb9000000, irq 4, mode:MII

Once I realised I should be using eth1 not eth0, at least.

The things I have learnt this week were almost entirely not about Nix: instead I was looking at the kernel, and the OpenWRT (actually LEDE-which-will-soon-be-OpenWRT-again) build process. Which was to some extent what I was originally trying to avoid by basing this whole thing on Nix, but there we are.

What's the problem?

The Linux kenel 4.14.1 has no support for the wired Ethernet device builtin to the AR933x SoC.

(I was actually quite surprised to find this out)

Do you have any plausible but unworkable suggestions to fix it?

Porting the driver from OpenWRT should be pretty simple. Just copy some files across and patch the Makefile, right?

I infer from your use of the words "simple" and "just" that it turns out to be a bit more complicated?

Damn, you know me too well.

I am you

True dat.


OpenWRT is based on the upstream kernel (score one over Android, at least) but diverges quite significantly, to the extent that the kernel stuff in the LEDE source repo contains about 250 extra source files you have to copy into your kernel source tree, and 2500 patch files that need to be applied on top. And a lot of the patches depend on previous patches in the series, and basically the upshot is that the chance of cherry-picking only the changes you want is kind of ... remote. At least certainly not without at least downloading and applying the whole series, by which time you have the whole series anyway.

There's another, slighty more long-term, problem with this suggestion, too: a tonne of those files are basically copy-paste jobs of each other, which makes me hope (admittedly against my own immediate self-interest) that upstream would refuse to adopt the resulting patch.

You're going to expound on this at tedious length, aren't you?

I'll try to keep it brief. Grown-up computers like PCs and SPARCs usually have standards by which an operating system may discover what hardware is attached/plugged in - PCI bus enumeration or Open Firmware or something like that. This is good because it means the kernel doesn't have to hardcode all this stuff. Embedded systems, on the other hand ...

... don't?

Often don't, no. Please stop finishing my sentences. So, historically, for every board or product that runs the Linux MIPS kernel, there is a chunk of code that registers all the devices and memory regions and all that stuff which the drivers will need, and this all gets a bit repetitive when there are a zillion of the buggers and they're all approximately the same but have slightly different base addresses for their USB ports, or they have two ethernets instead of 4, or the LEDs and the WPS buttons are hooked up to different GPIO pins.


Understandable in context, because what router manufacturer really cares that much that the same Linux kernel image will run across not only their entire product range but also the product ranges of seventeen of their competitors? But still, for our purposes a PITA.

So what can be done?

The Device Tree, or "why write code when you can write data?". First mooted back in 2009 and gradually (tending sometimes to grudgingly) accepted over the following nine years, the device tree for some particular board is essentially a serialisation of the data structures that Open Firmware would provide the OS when running on that board, in the hypothetical event that the board had Open Firmware. Upstream support for the ar71xx (a.k.a ath79) has rudimentary support for device tree, but no ethernet devices therein, and the old mach_* files have not yet been removed.

(Here's an example for the TL-MR3020 , a device almost-but-not-quite-identical to the Yun, which is too long to paste but definitely short enough that you should have a look at it)

So that's the Right Answer: add the ag71xx ethernet driver to the tree. Forward port it from 4.9 to 4.14, abstract somehow over the eleventy-billion-branch switch statements it's littered with so it works on multiple SoCs, decide what to do about the driver for the SoC's network switch that it relies on, and ponder whether to delete some mach_*.c files that clearly shouldn't be needed before deciding not to make that many needless enemies among the commercial users of this code.

Contrast, however, with the Pragmatic Answer: for the moment at least, until the circular tuit drought ends, why don't we switch to the OpenWRT kernel ? Which, as you can see from the printk output that started this entry, Already Just Works.

You said "just" again

Yeah. Sorry.


Pretty much. Also this week I made the kernel image build process a teeny bit less hacky, and added some frivolous stuff like cat, ifconfig and mount to the root filesystem, but that was basically trivial. And I posted to nix-devel about it and several people were quite kind.

Next stop, some userland - including the thorny question of what shall we use for an init system - and maybe some forward porting to make it work on nixpkgs master.

[ 1 week on: the next installment is here ]