Tackling Power Over Ethernet

Linux has no support for Power over Ethernet (PoE) in any way. There are many ethernet switches on the market that support PoE, and many of those switches run Linux, but none of those are supported in the mainline kernel, and their PoE support has not been upstreamed.

This situation is changing with the Realtek RTL83xx project. This series of SoCs is very popular, found in dozens of distinct models of many different vendors. The kernel code is coming together nicely. Many systems built on these chips support PoE, and this will need to be handled like any other feature on those chips. And there is much to support about PoE: number of ports, power modes, power budget, priority, and much more.

An opportunity thus represents itself: to create a new kernel subsystem and accompanying userspace tools, and have it automatically become the standard way of supporting PoE on Linux.

Let’s take a look at what’s needed.


The voltage on current-carrying lines of PoE ports is in a fundamentally different range, anywhere from 44V to 57V, than what a switch uses internally. The chip on the switch’s motherboard that provides this voltage is called the Power Sourcing Equipment (PSE) controller. It lives in a different power domain than the rest of the switch, typically with its own hookup to the system’s power supply. That means communication with these PSEs has to go via an electrically isolated path.

Generally the SoC doesn’t talk to the PSE directly; there’s a dedicated microcontroller of some sort that sits between them, mediating what the SoC can drive (often only UART) with what the PSE needs, such as I2C. In some cases these two form a product pair, such as the Microsemi PD69100/PD69108 management/PSE controllers, respectively. But usually the management microcontroller is something more generic, such as an STM32F100.

We’ll need to know the protocols the SoC has to speak to these different microcontrollers if we’re going to control PoE. It’s not always documented, but we’ve got a good handle on it. Indeed, the firmware running on these microcontrollers may turn out to be an interesting target for replacement with an open source version; crazier things have been done.


A PoE kernel subsystem should do the following:

  • Provide a framework for drivers that know about the protocol which the PSE, or its intermediate microcontroller, needs. Since the other endpoint of that protocol is dependent on the switch model, this information needs to live in the device tree. The drivers will also need to be aware of the firmware version on the other end, at least until we can replace it.

  • The device tree should also provide information about the model’s PoE capabilities, in order to mediate requests from userspace. Managing the power budget, for example, should be done here – no need to force every userspace client to keep track of this.

  • A userspace API, either via an ioctl on a device special file /dev/poe or perhaps a more modern sysfs interface. It’s easy enough to work out what this API should provide: whatever the PSE/MCU protocols provide must have an equivalent in this API. Additionally we can add discoverability to that: the userspace application should be able to find out which PoE capabilities the system has, on which ports.


While a userspace API is all good and well, using it involves awkward calls to ioctl, with lots of symbols pulled in from kernel headers, or lots of error-prone messing with sysfs files. That’s pretty laborious, and extra hard for scripting languages to tackle. A better way to handle this is to write a small library to sit in front of the awkward operations and symbol soup. A good example if this is libgpiod, which sits in front of the userspace interface to the kernel gpio subsystem. A library like this is also pretty easy to write language bindings for.

A quick and easy way to use PoE functionality from the shell is also a good idea. You need such a shell tool to test the library as it’s developed, anyway.

Writing a web interface that can work the system’s PoE functionality is then a matter of using the language bindings of the library as well. Easy!

I’m working on lots of different aspects of the Realtek RTL83xx kernel code at the moment, but this is an interesting enough opportunity that I think I need to get started on it – before somebody else does!