Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Embedded Recipes 2019 - Herd your socs become a matchmaker

80 views

Published on

About 60% of the Linux kernel source tree is devoted to drivers for a large variety of supported hardware components. Especially in the embedded world, the number of different SoC families, versions, and revisions, integrating a myriad of “IP cores”, keeps on growing.

In this presentation, Geert will explain how to match drivers against hardware, and how to support a wide variety of (dis)similar devices, without turning platform and driver code into an entangled bowl of spaghetti.tra

Starting with a brief history of driver matching in Linux, he will fast-forward to device-tree based matching. He will discuss ways to handle slight variations of the same hardware devices, and different SoC revisions, each with their own quirks and bugs. Finally, Geert will show best practices for evolving device drivers in a maintainable way, based on his experiences as an embedded Linux kernel developer and maintainer.
Geert Uytterhoeven

Published in: Software
  • Be the first to comment

  • Be the first to like this

Embedded Recipes 2019 - Herd your socs become a matchmaker

  1. 1. Herd Your Boards, Become a Farmer Embedded Recipes 2019 Geert Uytterhoeven geert@linux-m68k.org GLIDER bvba September 23, 2019 © Copyright 2019 GLIDER bvba, CC BY-SA 4.0
  2. 2. Herd Your SoCs, Become a Matchmaker Embedded Recipes 2019 Geert Uytterhoeven geert@linux-m68k.org GLIDER bvba September 23, 2019 © Copyright 2019 GLIDER bvba, CC BY-SA 4.0
  3. 3. Table of Contents Introduction History Device Tree Bindings Drivers Final Words 2 / 35
  4. 4. My Linux Subsystems Maintainer of Renesas clock and pin control drivers since 2016 Maintainer of Renesas ARM SoC platforms since July 2019 3 / 35
  5. 5. My Linux Subsystems Maintainer of Renesas clock and pin control drivers since 2016 Maintainer of Renesas ARM SoC platforms since July 2019 LTSI Submaintainer since July 2018 Maintainer of the m68k architecture since 2004 3 / 35
  6. 6. What Is Matching? Finding a suitable driver for a piece of hardware 4 / 35
  7. 7. What Is Matching? Finding a suitable driver for a piece of hardware + Identifying and using (all) available capabilities 4 / 35
  8. 8. What Is Matching? Finding a suitable driver for a piece of hardware + Identifying and using (all) available capabilities − Handling hardware-specific quirks/bugs/limitations 4 / 35
  9. 9. Table of Contents Introduction History Device Tree Bindings Drivers Final Words 5 / 35
  10. 10. A long time ago in a galaxy far, far away . . . x86 Kernel configuration: per-machine → not scalable! ISA probing 6 / 35
  11. 11. A long time ago in a galaxy far, far away . . . x86 Kernel configuration: per-machine → not scalable! ISA probing Multi-platform Machine type (m68k, MIPS, SPARC) Tagged bootinfo (m68k, ARM, MIPS) Info passed by bootloader or IDPROM 6 / 35
  12. 12. Rise of the Discoverable Buses Discoverable Buses PCI Zorro (Amiga) NuBus (Mac) SBUS (SPARC) . . . Image © 20th Century Fox 7 / 35
  13. 13. Rise of the Discoverable Buses Discoverable Buses PCI Zorro (Amiga) NuBus (Mac) SBUS (SPARC) . . . find() API pci_find_device() zorro_find_device() for_each_sbus{,dev}() . . . + Resource management request_{mem_}region() Image © 20th Century Fox 7 / 35
  14. 14. Device Framework (2001) Triggered by hot-pluggable buses (e.g. USB) Separation bus / device / driver pci_{device,driver} zorro_{device,driver} platform_{device,driver} . . . Core matches devices to drivers based on IDs 8 / 35
  15. 15. Device Framework (2001) Triggered by hot-pluggable buses (e.g. USB) Separation bus / device / driver pci_{device,driver} zorro_{device,driver} platform_{device,driver} . . . Core matches devices to drivers based on IDs match() API struct bus_type { int (*match)(struct device *dev, struct device_driver *drv); }; 8 / 35
  16. 16. Embedded: Return Of The Non-Discoverable Buses Non-Discoverable Buses Growing integration: SoC Exponentially growing number of SoC families, versions, and revisions Standardized components on board Hardware description: board files with platform_device + platform_data Linus’ 2010 rant about ARM churn Image © 20th Century Fox 9 / 35
  17. 17. Device Tree Real Open Firmware Flattened Device Tree Device ⇔ device node Compatible value(s) Standard properties (resources, . . . ) Custom properties Phandles Subnodes Clear separation between Hardware Description and OS Configuration Stable DT ABI Ties into platform_device 10 / 35
  18. 18. DT Early Adopters Straight conversion from platform_data to DT properties Same compatible value, many feature properties ⇒ All detail in DT CCF: Collection of device nodes for on-SoC clock generator Standard and custom parts Individual bits described in DT 11 / 35
  19. 19. DT Early Adopters Straight conversion from platform_data to DT properties Same compatible value, many feature properties ⇒ All detail in DT CCF: Collection of device nodes for on-SoC clock generator Standard and custom parts Individual bits described in DT Caveats You will forget to describe a difference, difficult to fix later! New SoC reuses block with e.g. different predivider ⇒ DT property Newer block with different predivider now also supported! What if another difference is discovered later? 11 / 35
  20. 20. DT Evolution/Maturity More different compatible values, few/no feature properties Clocks: "monolithic" device node for on-SoC clock generator ⇒ Easier to extend/maintain 12 / 35
  21. 21. DT Evolution/Maturity More different compatible values, few/no feature properties Clocks: "monolithic" device node for on-SoC clock generator ⇒ Easier to extend/maintain ELCE2014: Engaging Device Trees Still good? 12 / 35
  22. 22. DT Evolution/Maturity More different compatible values, few/no feature properties Clocks: "monolithic" device node for on-SoC clock generator ⇒ Easier to extend/maintain ELCE2014: Engaging Device Trees Still good? Yes! (surprisingly?) Clocks: Moved from collection of nodes to a monolithic approach (DT without Common Clock Framework is dead) Power Domains: similar, but didn’t have DT bindings yet https://elinux.org/ELC_2014_Presentations 12 / 35
  23. 23. soc_device_match() (2016) Different approach, in-kernel Wildcards! If all else fails. . . struct soc_device_attribute { const char *machine; const char *family; const char *revision; const char *serial_number; const char *soc_id; const void *data; }; const struct soc_device_attribute *soc_device_match( const struct soc_device_attribute *matches); 13 / 35
  24. 24. Table of Contents Introduction History Device Tree Bindings Drivers Final Words 14 / 35
  25. 25. Designing Compatible Value Schemes The Original Series Basic Idea Multiple compatible values: most-specific to least-specific Driver matches against what is supported 15 / 35
  26. 26. Designing Compatible Value Schemes The Original Series Basic Idea Multiple compatible values: most-specific to least-specific Driver matches against what is supported Original: current version + older compatible version Suitable for slow evolution E.g. 8250 → 16450 → 16550 UART Bad example! Discrete components E.g. WLAN controller 15 / 35
  27. 27. Designing Compatible Value Schemes A Brave New World Fast Evolution Building an SoC ∼ LEGO, Kconfig Complex heritage hierarchy (copy and corrupt^Wmodify) Which one is predecessor/successor? Do all family members have the same version? 16 / 35
  28. 28. Designing Compatible Value Schemes A Brave New World Fast Evolution Building an SoC ∼ LEGO, Kconfig Complex heritage hierarchy (copy and corrupt^Wmodify) Which one is predecessor/successor? Do all family members have the same version? SiFive sifive,<ip-block-name><integer version number> E.g. sifive,uart0 16 / 35
  29. 29. Example: Renesas DT Bindings For On-SoC Devices 1. SoC-specific (always, unless version register present) E.g. renesas,r8a7791-sysc, renesas,r8a7795-wdt → To anticipate unknown differences 2. Family-specific (usually) E.g. renesas,rcar-gen2-scif 3. Generic (sometimes: legacy or version register) E.g. renesas,scif or renesas,vsp2 17 / 35
  30. 30. Example: Renesas DT Bindings For On-SoC Devices 1. SoC-specific (always, unless version register present) E.g. renesas,r8a7791-sysc, renesas,r8a7795-wdt → To anticipate unknown differences 2. Family-specific (usually) E.g. renesas,rcar-gen2-scif 3. Generic (sometimes: legacy or version register) E.g. renesas,scif or renesas,vsp2 DT bindings document all of the above (checkpatch.pl!) DTS advertizes all of the above Driver matches against least-specific that will do the job 17 / 35
  31. 31. Renesas DT Compatible Values: Statistics Linux v5.3: Type Documented Used Matched SoC-specific 743 688 296 Family-specific 92 82 85 Generic 30 29 28 18 / 35
  32. 32. Renesas DT Compatible Values: Statistics Linux v5.3: Type Documented Used Matched SoC-specific 743 688 296 Family-specific 92 82 85 Generic 30 29 28 Is proliferation of compatible values, and churn on the DT binding documents, worth it? 18 / 35
  33. 33. Example: Differences Within The Same Family Obvious for e.g. clocks, power domains, pin controllers, Unexpected (R-Car Gen3 only): DRIF Extra register on M3-N and E3, LVDS Not uniform, unlike on Gen2, PCIe Extra PHY register on V3H, RPC-IF Several differences, Sound R-Car E3 special handling was bolted on later, Thermal M3-W turned out to have a different Tj, USBHS Wrongly assumed identical to Gen2, E3/D3 use a different PLL, VIN Not uniform, unlike on Gen2. Compare: 23 family-specific values for R-Car Gen3. 19 / 35
  34. 34. Table of Contents Introduction History Device Tree Bindings Drivers Final Words 20 / 35
  35. 35. Supporting a Variety of Similar Devices Similar devices on (a family of) SoCs may have: Slightly differing feature sets Quirks/bugs 21 / 35
  36. 36. Supporting a Variety of Similar Devices Similar devices on (a family of) SoCs may have: Slightly differing feature sets Quirks/bugs Differentiate by: Compatible value Machine, family, revision, serial number, soc_id + wildcards (e.g. .revision = "ES1.*") Device address? 21 / 35
  37. 37. Supporting a Variety of Similar Devices Similar devices on (a family of) SoCs may have: Slightly differing feature sets Quirks/bugs Differentiate by: Compatible value Machine, family, revision, serial number, soc_id + wildcards (e.g. .revision = "ES1.*") Device address? Solutions 1. Match on compatible value 2. struct soc_device_attribute and soc_device_match() 21 / 35
  38. 38. Quirk Classes Variant-Specific How to handle? Device compatible value Example: New or missing features 22 / 35
  39. 39. Quirk Classes Variant-Specific How to handle? Device compatible value Example: New or missing features SoC-Specific / SoC Integration Issue How to handle? Device compatible value soc_device_match() Example: Broken DMA on early revision 22 / 35
  40. 40. Quirk Classes Instance-Specific One instance on SoC affected How to handle? Device base address + soc_device_match() DT property / Device compatible value Example: Broken interrupt on one instance 23 / 35
  41. 41. Quirk Classes Instance-Specific One instance on SoC affected How to handle? Device base address + soc_device_match() DT property / Device compatible value Example: Broken interrupt on one instance Board-Specific How to handle? Board compatible value Example: R-Car Gen2 regulator quirk 23 / 35
  42. 42. Matching Methods 1. platform_driver.driver.of_match_table 24 / 35
  43. 43. Matching Methods 1. platform_driver.driver.of_match_table 2. *_OF_DECLARE() Early (for clocks, timers, irqchips) X Dependencies on clocks/power domains/interrupts X No -EPROBE_DEFER Mixed: CLK_OF_DECLARE_DRIVER 24 / 35
  44. 44. Matching Methods 1. platform_driver.driver.of_match_table 2. *_OF_DECLARE() Early (for clocks, timers, irqchips) X Dependencies on clocks/power domains/interrupts X No -EPROBE_DEFER Mixed: CLK_OF_DECLARE_DRIVER 3. for_each_compatible_node() of_find_compatible_node() of_find_matching_node() of_device_is_compatible() 24 / 35
  45. 45. Matching Methods 1. platform_driver.driver.of_match_table 2. *_OF_DECLARE() Early (for clocks, timers, irqchips) X Dependencies on clocks/power domains/interrupts X No -EPROBE_DEFER Mixed: CLK_OF_DECLARE_DRIVER 3. for_each_compatible_node() of_find_compatible_node() of_find_matching_node() of_device_is_compatible() 4. soc_device_match() 24 / 35
  46. 46. Naive/Bad Examples if (of_device_is_compatible(np, "myvendor,mydev")) { ... } if (soc_device_match(&myrev1) || soc_device_match(&myrev2)) { ... } 25 / 35
  47. 47. Naive/Bad Examples if (of_device_is_compatible(np, "myvendor,mydev")) { ... } if (soc_device_match(&myrev1) || soc_device_match(&myrev2)) { ... } Called multiple times? From an interrupt handler? Not scalable! 25 / 35
  48. 48. Example: Scalar Feature Mask drivers/clk/renesas/rcar-gen3-cpg.c static const struct soc_device_attribute cpg_quirks_match[] = { { .soc_id = "r8a7795", .revision = "ES1.0", .data = (void *)(PLL_ERRATA | RCKCR_CKSEL | ...), }, ... }; int rcar_gen3_cpg_init(...) { const struct soc_device_attribute *attr; attr = soc_device_match(cpg_quirks_match); if (attr) cpg_quirks = (uintptr_t)attr->data; } // Later... if (cpg_quirks & ...) { ... } 26 / 35
  49. 49. Example: Feature Structure, Combined drivers/media/platform/rcar-vin/rcar-core.c static const struct of_device_id rvin_of_id_table[] = { { .compatible = "renesas,vin-r8a7795", .data = &rcar_info_r8a7795, }, ... }; static const struct soc_device_attribute r8a7795es1[] = { { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_info_r8a7795es1, }, ... }; static int rcar_vin_probe(struct platform_device *pdev) { vin->info = of_device_get_match_data(&pdev->dev); attr = soc_device_match(r8a7795es1); if (attr) vin->info = attr->data; } 27 / 35
  50. 50. Different DTSes For Different SoC Revisions Include new SoC .dtsi in old .dtsi Add/override nodes and properties /delete-node/, /delete-property/ Use soc_device_match() to differentiate 28 / 35
  51. 51. Different DTSes For Different SoC Revisions Include new SoC .dtsi in old .dtsi Add/override nodes and properties /delete-node/, /delete-property/ Use soc_device_match() to differentiate Example R-Car H3 ES1.x (R8A77950) and ES2.0 (R8A77951) both use r8a7795-based compatible values In hindsight: ES2.0 is a new SoC, not just a fixed ES1.x New r8a77951-based compatible values 28 / 35
  52. 52. Table of Contents Introduction History Device Tree Bindings Drivers Final Words 29 / 35
  53. 53. Has DT improved the ARM situation? Evolution of the number of ARM defconfig files (ELC2014) 0 20 40 60 80 100 120 140 160 180 v2.6.14 v2.6.19 v2.6.24 v2.6.29 v2.6.34 v2.6.39 v3.4 v3.9 v3.14 30 / 35
  54. 54. Has DT improved the ARM situation? Evolution of the number of ARM defconfig files 0 20 40 60 80 100 120 140 160 180 v2.6.14v2.6.19v2.6.24v2.6.29v2.6.34v2.6.39v3.4 v3.9 v3.14 v3.19 v4.4 v4.9 v4.14 v4.19 v5.3 31 / 35
  55. 55. Has DT improved the ARM situation? Evolution of the number of ARM DTS files 0 200 400 600 800 1000 1200 v3.4 v3.9 v3.14 v3.19 v4.4 v4.9 v4.14 v4.19 v5.3 arm32 arm64 32 / 35
  56. 56. Has DT improved the ARM situation? Evolution of the number of lines in ARM board files and ARM DTS files 0 100000 200000 300000 400000 500000 600000 v2.6.14v2.6.19v2.6.24v2.6.29v2.6.34v2.6.39v3.4 v3.9 v3.14 v3.19 v4.4 v4.9 v4.14 v4.19 v5.3 arm32 board arm32 DTS arm64 DTS 33 / 35
  57. 57. Thanks & Acknowledgements Renesas Electronics Corporation, for contracting me for upstream Linux kernel work, Embedded Recipes, for organizing this conference and giving me the opportunity to present here, The Linux Kernel Community, for having so much fun working together towards a common goal. 34 / 35
  58. 58. Questions? ? 35 / 35

×