\documentclass[obeyspaces,spaces,hyphens]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{minted}

\mode<presentation>
\usetheme{Bootlin}

\newcommand{\codehack}[1]{{\usebeamercolor[fg]{code} {\tt #1}}}

\title{Device Tree as a stable ABI: a fairy tale?}
\authors{Thomas Petazzoni}
\institute{Bootlin}

\usepackage{hyperref}

\newcounter{lessonno}

\begin{document}

\begin{frame}{Embedded Linux Conference 2015}
  \begin{columns}[c]
    \column{0.6\textwidth}
    \huge
    Device Tree as a stable ABI: a fairy tale?\\
    \vspace{2cm}
    \normalsize
    Thomas Petazzoni\\
    {\bf Bootlin}\\
    {\em thomas.petazzoni@bootlin.com}
    \column{0.4\textwidth}
    \includegraphics[width=\textwidth]{tree.jpg}
  \end{columns}
\end{frame}

\begin{frame}{Thomas Petazzoni}
  \begin{columns}
    \column{0.7\textwidth}
  \begin{itemize}
  \item CTO and Embedded Linux engineer at {\bf Bootlin}
    \begin{itemize}
    \item Embedded Linux specialists.
    \item Development, consulting and training.
    \item \url{http://bootlin.com}
    \end{itemize}
  \item Contributions
    \begin{itemize}
    \item {\bf Kernel support for the Marvell Armada} ARM SoCs from
      Marvell
    \item Major contributor to {\bf Buildroot}, an open-source, simple and
      fast embedded Linux build system
    \end{itemize}
  \item Living in {\bf Toulouse}, south west of France
  \end{itemize}
  \column{0.3\textwidth}
  \includegraphics[width=0.9\textwidth]{2penguins.png}\\
  \includegraphics[width=0.9\textwidth]{armada.jpg}\\
  \includegraphics[width=0.9\textwidth]{buildroot.png}
\end{columns}
\end{frame}

\begin{frame}{Context}
  \begin{itemize}
  \item ARM platforms have been switching to a {\em Device Tree} based
    hardware representation for a few years.
  \item Intended goals
    \begin{itemize}
    \item get rid of numerous board files
    \item encourage  the usage of generic subsystems instead of arch-specific
      solutions
    \item and make multiplatform support easier
    \item $\rightarrow$ quite successful in those goals!
    \end{itemize}
  \item But the usage of the {\em Device Tree} on ARM also came with a
    requirement: it should be a {\bf stable ABI}
    \begin{itemize}
    \item An old Device Tree for a given hardware platform must
      continue to work with newer kernel versions.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Assumptions}
  \begin{itemize}
  \item Handling backward compatibility is easy
    \begin{itemize}
    \item ``{\em Just handle a default behavior to be compatible with
        the old situation}''
    \end{itemize}
  \item Having stable Device Tree is needed by the users: hardware
    vendors, distributions
  \item Good review by a team of Device Tree bindings maintainers will
    make sure the bindings are good enough to be stable.
  \end{itemize}
\end{frame}

\begin{frame}{Backward compatibility is easy?}
  \begin{itemize}
  \item Yes, if the change in your binding is just to add a new
    property.
  \item But what if
    \begin{itemize}
    \item you need to add new nodes?
    \item {\em phandles} pointing to them?
    \item re-organize nodes to use \code{simple-mfd}?
    \item ...
    \end{itemize}
  \item Causes:
    \begin{itemize}
    \item Undocumented or poorly documented hardware: no datasheet,
      only vendor BSP code available
    \item Badly understood hardware: information was available, but
      was somehow overlooked.
    \item Simply badly designed bindings.
    \end{itemize}
  \item We'll go through a number of examples to illustrate those
    cases.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell Berlin BG2Q system control IP (1)}
  \small
  \begin{columns}
    \column{0.5\textwidth}
  \begin{itemize}
  \item No datasheet available, work is done based on vendor kernel
    code + datasheets of older SoCs that are sometimes similar,
    sometimes not.
  \item A set of registers called {\em System control} that controls
    the muxing of a number of pins.
  \item A classical DT representation:
  \item And a {\em pinctrl} \code{platform_driver} matching against
    this compatible string.
  \item So far, so good.
  \end{itemize}
  \column{0.5\textwidth}
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
sysctrl: pin-controller@d000 {
    compatible = "marvell,berlin2q-system-ctrl";
    reg = <0xd000 0x100>;

    uart0_pmux: uart0-pmux {
        groups = "GSM12";
        function = "uart0";
    };

    uart1_pmux: uart1-pmux {
        groups = "GSM14";
        function = "uart1";
    };
};
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{Marvell Berlin BG2Q system control IP (2)}
  \small
  \begin{columns}
    \column{0.5\textwidth}
  \begin{itemize}
  \item Much later, asked to work on supporting the ADC.
  \item Turns out the ADC registers are part of the same {\em System
      control} registers.
  \item Ah, great there is new \code{simple-mfd} Device Tree binding
    proposed by Linus Walleij. Exactly does what we need.
  \item Works fine, but how to handle {\em backward compatibility}
    when DT nodes are re-organized this way?
  \end{itemize}
  \column{0.5\textwidth}
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
sysctrl: system-controller@d000 {
    compatible = "marvell,berlin2q-system-ctrl",
                 "simple-mfd", "syscon";
    reg = <0xd000 0x100>;

    sys_pinctrl: pin-controller {
        compatible =
            "marvell,berlin2q-system-pinctrl";

        uart0_pmux: uart0-pmux {
            groups = "GSM12";
            function = "uart0";
        };
        [...]
    };

    adc: adc {
       compatible = "marvell,berlin2-adc";
       interrupt-parent = <&sic>;
       interrupts = <12>, <14>;
       interrupt-names = "adc", "tsen";
    };
};
      \end{minted}
    \end{block}
  \end{columns}
  \begin{itemize}
  \item Similar, but even more complicated situation with the {\em
      Chip Control} registers: pin-muxing, reset, clocks.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Allwinner MMC clock phase (1)}
  \begin{itemize}
  \item No datasheet, only vendor code.
  \item Originally: one clock for the MMC, plus some {\em magic bits}
    controlling two phases: {\em output phase} and {\em sample phase}.
  \item Represented as one clock \code{mmcX_clk}
    \begin{block}{}
      \begin{minted}[fontsize=\footnotesize]{perl}
clocks = <&ahb_gates 8>, <&mmc0_clk>;
clock-names = "ahb", "mmc";
\end{minted}
\end{block}
\item Custom clock API used to control both the {\em output phase} and {\em
    sample phase}, used by the MMC driver.
  \begin{block}{}
    \begin{minted}[fontsize=\footnotesize]{c}
clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
    \end{minted}
  \end{block}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Allwinner MMC clock phase (2)}
  \begin{itemize}
  \item Contacted the vendor, and after lots of efforts, finally got
    some details.
  \item In fact, the {\em output} and {\em sample} parameters are
    clocks by themselves: so there are three clocks and not one.
  \item Moved to a three clocks model:
    \begin{block}{}
      \begin{minted}[fontsize=\scriptsize]{perl}
clocks = <&ahb_gates 8>, <&mmc0_clk 0>, <&mmc0_clk 1>, <&mmc0_clk 2>;
clock-names = "ahb", "mmc", "output", "sample";
\end{minted}
\end{block}
\item And a generic clock framework API:
  \begin{block}{}
    \begin{minted}[fontsize=\footnotesize]{c}
clk_set_phase(host->clk_sample, sclk_dly);
clk_set_phase(host->clk_output, oclk_dly);
    \end{minted}
  \end{block}
\item To keep DT backward compatibility, options are:
  \begin{itemize}
  \item Keep an ugly non-accurate HW representation
  \item Carry lots of legacy (and never tested) code in the MMC and
    clock drivers
  \end{itemize}
\end{itemize}
\end{frame}

\begin{frame}{Marvell window 13 issue (1)}
  \begin{itemize}
  \item Marvell processors have a concept of {\em configurable
      windows}
  \item You define a base address, a size, and a target device (NOR,
    PCIe device, BootROM, SRAM, etc.) and the device appears in
    physical memory.
  \item Some of the windows have a {\em remap} capability. In addition
    to the {\em base address} visible from the CPU side, you can
    define a {\em remap address} which is the device visible address.
  \item Each window has {\em control} and {\em base} registers
  \item Remappable windows also have {\em remap high} and {\em remap
      low registers}
  \item Not configuring those {\em remap} registers when available
    lead to an unusable window.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell window 13 issue (2)}
  \begin{itemize}
  \item At first sight, Armada 370, 375, 38x and XP looked the same.
  \item They have 20 windows, of which the first 8 have the remap
    capability.
  \item So, in all Device Tree files, we used:
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
compatible = "marvell,armada380-mbus", "marvell,armada370-mbus", "simple-bus";
      \end{minted}
    \end{block}
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
compatible = "marvell,armada375-mbus", "marvell,armada370-mbus", "simple-bus";
      \end{minted}
    \end{block}
  \item Originally, only the \code{marvell,armada370-mbus} was matching.
  \item Later, we discovered that Armada XP, 375 and 38x had a {\em
      remappable} window 13.
  \item You need a different handling of window 13 between Armada 370
    on one side, and Armada XP/375/38x on the other side.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell window 13 issue (3)}
  \begin{itemize}
  \item Thanks to the provision of a more SoC-specific compatible
    string, we could override the behavior for Armada XP, Armada 375,
    Armada 38x.
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
compatible = "marvell,armada375-mbus", "marvell,armada370-mbus", "simple-bus";
      \end{minted}
    \end{block}
  \item However, \code{marvell,armada370-mbus} remains in the
    compatible list, which is incorrect.
    \begin{itemize}
    \item Armada XP/375/38x functionality is {\bf not} a super set of
      Armada 370 functionality.
    \item Using the Armada 370 {\em MBus} behavior on Armada XP, 375
      and 38x is a bug.
    \end{itemize}
  \item Not a backward compatibility problem, but shows that one can
    easily overlook minor differences between SoC revisions that make
    similar hardware blocks incompatible.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell CPU reset IP}
  \begin{itemize}
  \item On Armada XP, enabling SMP requires fiddling with the {\em
      Power Management Service Unit} (PMSU) and CPU reset registers.
  \item So, we created a Device Tree node:
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
armada-370-xp-pmsu@22000 {
    compatible = "marvell,armada-370-xp-pmsu";
    reg = <0x22100 0x400>, <0x20800 0x20>;
};
      \end{minted}
    \end{block}
  \item The first register area is the PMSU, the second are the CPU
    reset bits.
  \item One {\em driver}, \code{pmsu.c}, was mapping those registers,
    and providing the necessary functions for SMP enabling.
  \item We introduced this in Linux 3.8, at a time where there was no
    {\em reset framework} $\rightarrow$ no use of the {\em reset} DT
    binding.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell CPU reset IP (2)}
  \small
  \begin{columns}
    \column{0.6\textwidth}
  \begin{itemize}
  \item Then came the Armada 375.
    \begin{itemize}
    \item It has the exact same CPU reset bits, but does not have a
      PMSU.
    \end{itemize}
  \item Clearly, one DT node for both registers areas was a mistake, so
    we splitted in two nodes.
  \item We kept backward compatibility code in the new {\em CPU reset}
    driver, by looking for the register addresses in the second {\em
      reg} of \code{marvell,armada-370-xp-pmsu}.
  \end{itemize}
  \column{0.4\textwidth}
    \begin{block}{}
      \begin{minted}[fontsize=\tiny]{perl}
pmsu@22000 {
    compatible =
      "marvell,armada-370-pmsu";
    reg = <0x22000 0x1000>;
};

cpurst@20800 {
    compatible =
      "marvell,armada-370-cpu-reset";
    reg = <0x20800 0x20>;
};
      \end{minted}
    \end{block}
  \end{columns}
  \begin{itemize}
      \item This example is more a design mistake from the developers, but
    doesn't this happens?
  \item Shouldn't the review have pointed out the
    stupidity of one DT nodes for two different hardware blocks?
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell CPU reset IP (3)}
  \begin{itemize}
  \item Ideally, we would like to use the CPU reset framework and its
    Device Tree binding, now that it exists?
  \item Refactoring code to use more modern framework is what good
    kernel citizens should do, no?
  \item Except that using the CPU reset framework involves creating
    \code{resets} {\em phandles} pointing to the reset controller
    node.
  \item And in our case, the {\em reset controller} node did not exist
    in the old DT, since it was mistakenly mixed with the PMSU node.
  \item Moving to the CPU reset framework {\em and} supporting
    backward compatibility would have required:
    \begin{itemize}
    \item Dynamically creating the CPU reset node, with at least a
      \code{#reset-cells} property.
    \item Dynamically adding the \code{resets} properties to each CPU,
      with a phandle pointing to the CPU reset node.
    \end{itemize}
  \item $\rightarrow$ in the end we gave up and simply did not use the
    {\em reset framework}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Marvell CPU reset IP (4)}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{block}{Old DT}
      \begin{minted}[fontsize=\tiny]{perl}
cpus {
        cpu@0 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <0>;
        };

        cpu@1 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <1>;
        };
};

armada-370-xp-pmsu@22000 {
        compatible = "marvell,armada-370-xp-pmsu";
        reg = <0x22100 0x400>, <0x20800 0x20>;
};
      \end{minted}
    \end{block}
    \column{0.5\textwidth}
    \begin{block}{New non-ideal DT}
      \begin{minted}[fontsize=\tiny]{perl}
cpus {
        cpu@0 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <0>;
        };

        cpu@1 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <1>;
        };
};

pmsu@22000 {
        compatible = "marvell,armada-370-pmsu";
        reg = <0x22000 0x1000>;
};

cpurst@20800 {
        compatible = "marvell,armada-370-cpu-reset";
        reg = <0x20800 0x20>;
};
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{Marvell CPU reset IP (5)}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{block}{Old DT}
      \begin{minted}[fontsize=\tiny]{perl}
cpus {
        cpu@0 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <0>;
        };

        cpu@1 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <1>;
        };
};

armada-370-xp-pmsu@22000 {
        compatible = "marvell,armada-370-xp-pmsu";
        reg = <0x22100 0x400>, <0x20800 0x20>;
};
      \end{minted}
    \end{block}
    \column{0.5\textwidth}
    \begin{block}{Ideal DT}
      \begin{minted}[fontsize=\tiny]{perl}
cpus {
        cpu@0 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <0>;
                resets = <&cpurst 0>;
        };

        cpu@1 {
                device_type = "cpu";
                compatible = "marvell,sheeva-v7";
                reg = <1>;
                resets = <&cpurst 1>;
        };
};

cpurst: cpurst@20800 {
        compatible = "marvell,armada-370-cpu-reset";
        reg = <0x20800 0x20>;
        #reset-cells = <1>;
};

pmsu@22000 {
        compatible = "marvell,armada-370-pmsu";
        reg = <0x22000 0x1000>;
};
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}{A timing problem (1)}
  \begin{center}
  Idea behind stable DT bindings:
  \vspace{1cm}

  Hardware vendors can ship the hardware with a DT describing the
  platform, and any recent kernel version will work with it, thanks to
  the DT bindings being a stable ABI.
  \end{center}
\end{frame}

\begin{frame}{A timing problem (2)}
  \begin{center}
    \includegraphics[width=\textwidth]{timing.pdf}
  \end{center}
\end{frame}

\begin{frame}{A timing problem (3)}
  \begin{itemize}
  \item Do we really want to let hardware vendors define what DT
    bindings should be?
  \item Without review from the community?
  \item Really?
  \item Or should we speed up the upstreaming process?
  \item But how is this compatible with taking the time to define
    proper DT bindings that will be stable?
  \end{itemize}
\end{frame}

\begin{frame}{Enough review?}
  \begin{itemize}
  \item Stability of the system call ABI is achieved by careful review
    of the proposed changes.
  \item What amount of review do we have for DT bindings?
  \end{itemize}
  \begin{center}
    \includegraphics[width=\textwidth]{dt-bindings-review.eps}
  \end{center}
\end{frame}

\begin{frame}{Testing?}
  \begin{itemize}
  \item Maintaining backward compatibility requires a {\bf lot} of
    code in device drivers to handle old DT bindings.
  \item No, not just a simple fall back to a default behavior when
    property {\em foo} is not here.
  \item Who will test this code?
  \item Most likely nobody, it will be dead, untested, unmaintained
    code.
  \item At a time where \code{devm_*} functions are generalized to
    avoid mistakes in untested error handling, we're adding huge
    amounts of backward compatibility code.
  \item Is that really reasonable?
  \end{itemize}
\end{frame}

\begin{frame}{Usefulness}
  \begin{itemize}
  \item For Linux distros?
    \begin{itemize}
    \item Fedora is installing DTBs in \code{/boot/dtb-<kernel-version>/}
    \item E.g: \code{/boot/dtb-3.11.10-301.fc20.armv7hl/vexpress-v2p-ca9.dtb}
    \end{itemize}
  \item For hardware vendors?
    \begin{itemize}
    \item From
      \code{Documentation/arm/Atmel/README}: {\em Device Tree files and Device Tree bindings that apply to AT91 SoCs and boards are considered as "Unstable". To be completely clear, any at91 binding can change at any time. So, be sure to use a Device Tree Binary and a Kernel Image generated from the same source tree.}
    \item Atmel is one of the most well supported platform in
      mainline, with excellent fully public datasheets, and slow
      evolution of the SoC family.
    \item And still they want their bindings to not be stable.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Comparing to the system call ABI}
  \begin{itemize}
  \item Kernel developers already consider maintaining the system call
    backward compatibility to be a difficult exercise.
  \item Lot of review and discussion before introducing a new system
    call.
  \item Lots of testing naturally happening, since mixing userspace /
    kernel versions is the default way of using Linux.
  \item The {\em surface} of the system call ABI is much more narrow,
    and not directly tied to constantly changing hardware details.
  \end{itemize}
\end{frame}

\begin{frame}{Reality}
\begin{exampleblock}{}
  {\large ``So embedded people are going to ship with unfinished DT and
  upgrade later. They have to. There is no choice. Stable DT doesn't
  change anything unless you can create perfect stable bindings for a
  new SOC instantaneously.''}
  \vskip5mm
  \hspace*\fill{\small--- Jason Gunthorpe}
\end{exampleblock}
\end{frame}

\begin{frame}{Conclusion}
  \begin{itemize}
  \item Maintaining Device Tree backward compatibility
    \begin{itemize}
    \item has a high cost in maintenance and testing effort
    \item prevents refactoring code to use new generic kernel
      frameworks
    \item is not used by Linux distributions, not wanted by hardware
      vendors
    \item has no chance to work due to the timing of product
      development vs. speed of upstreaming
    \end{itemize}
  \item So: should we really care?
  \end{itemize}
\end{frame}

\begin{frame}
  \begin{center}
    \includegraphics[height=0.4\textheight]{popcorn.jpg}\\
    \vspace{1cm}
    \large
    \hfill \code{thomas.petazzoni@bootlin.com} \hfill
    \vspace{0.2cm}
    \newline Slides under CC-BY-SA 3.0\\
    \vspace{0.2cm}
    \scriptsize
    \url{http://bootlin.com/pub/conferences/2015/elc/petazzoni-dt-as-stable-abi-fairy-tale/}
  \end{center}
\end{frame}

\end{document}
