فهرست منبع

releaseversion

Reinhard Russinger 5 سال پیش
والد
کامیت
cfc8dfc42f
56فایلهای تغییر یافته به همراه4350 افزوده شده و 41 حذف شده
  1. 1 0
      Config.in
  2. 2 2
      board/PSG/iot2000/linux-4.4-patches/0001-stmmac-pci-Make-stmmac_pci_info-structure-constant.patch
  3. 2 2
      board/PSG/iot2000/linux-4.4-patches/0002-stmmac-pci-Use-stmmac_pci_info-for-all-devices.patch
  4. 2 2
      board/PSG/iot2000/linux-4.4-patches/0003-stmmac-pci-Make-stmmac_pci_find_phy_addr-truly-gener.patch
  5. 2 2
      board/PSG/iot2000/linux-4.4-patches/0004-stmmac-pci-Select-quark_pci_dmi_data-from-quark_defa.patch
  6. 2 2
      board/PSG/iot2000/linux-4.4-patches/0005-stmmac-pci-Use-dmi_system_id-table-for-retrieving-PH.patch
  7. 2 2
      board/PSG/iot2000/linux-4.4-patches/0006-stmmac-pci-Adjust-IOT2000-matching.patch
  8. 2 2
      board/PSG/iot2000/linux-4.4-patches/0007-serial-8250_exar-Adjust-IOT2000-matching.patch
  9. 2 2
      board/PSG/iot2000/linux-4.4-patches/0008-mfd-intel_quark_i2c_gpio-Adjust-IOT2000-matching.patch
  10. 2 2
      board/PSG/iot2000/linux-4.4-patches/0009-gpio-sch-use-gpiochip-data-pointer.patch
  11. 2 2
      board/PSG/iot2000/linux-4.4-patches/0010-gpio-sch-Use-devm_gpiochip_add_data-for-gpio-registr.patch
  12. 2 2
      board/PSG/iot2000/linux-4.4-patches/0011-gpio-sch-Fix-Oops-on-module-load-on-Asus-Eee-PC-1201.patch
  13. 2 2
      board/PSG/iot2000/linux-4.4-patches/0012-gpio-sch-Implement-.get_direction.patch
  14. 2 2
      board/PSG/iot2000/linux-4.4-patches/0013-gpio-sch-Add-interrupt-support.patch
  15. 2 2
      board/PSG/iot2000/linux-4.4-patches/0014-iot2000-hack-Work-around-DSDT-mistake.patch
  16. 2 2
      board/PSG/iot2000/linux-4.4-patches/0015-iot2000-hack-Adjust-pca9685-gpio-base-for-legacy-com.patch
  17. 2 2
      board/PSG/iot2000/linux-4.4-patches/0016-iot2000-hack-gpio-pca953x-provide-GPIO-base-based-on.patch
  18. 6 6
      board/PSG/iot2000/linux-4.4-patches/0017-iot2000-hack-gpio-pca953x-add-drive-property.patch
  19. 2 2
      board/PSG/iot2000/linux-4.4-patches/0018-iot2000-hack-pwm-pca-9685-Provide-chip-level-pwm_per.patch
  20. 801 0
      board/PSG/iot2000/linux-4.4-patches/0019-random-replace-non-blocking-pool-with-a-Chacha20-bas.patch
  21. 143 0
      board/PSG/iot2000/linux-4.4-patches/0020-random-make-dev-urandom-scalable-for-silly-userspace.patch
  22. 109 0
      board/PSG/iot2000/linux-4.4-patches/0021-random-add-backtracking-protection-to-the-CRNG.patch
  23. 35 0
      board/PSG/iot2000/linux-4.4-patches/0022-random-remove-stale-maybe_reseed_primary_crng.patch
  24. 180 0
      board/PSG/iot2000/linux-4.4-patches/0023-random-use-chacha20-for-get_random_int-long.patch
  25. 147 0
      board/PSG/iot2000/linux-4.4-patches/0024-random-convert-get_random_int-long-into-get_random_u.patch
  26. 148 0
      board/PSG/iot2000/linux-4.4-patches/0025-random-invalidate-batched-entropy-after-crng-init.patch
  27. 87 0
      board/PSG/iot2000/linux-4.4-patches/0026-random-silence-compiler-warnings-and-fix-race.patch
  28. 118 0
      board/PSG/iot2000/linux-4.4-patches/0027-random-add-wait_for_random_bytes-API.patch
  29. 77 0
      board/PSG/iot2000/linux-4.4-patches/0028-random-fix-crng_ready-test.patch
  30. 110 0
      board/PSG/iot2000/linux-4.4-patches/0029-random-use-a-different-mixing-algorithm-for-add_devi.patch
  31. 163 0
      board/PSG/iot2000/linux-4.4-patches/0030-random-only-read-from-dev-random-after-its-pool-has-.patch
  32. 58 0
      board/PSG/iot2000/linux-4.4-patches/0031-random-fix-soft-lockup-when-trying-to-read-from-an-u.patch
  33. 145 0
      board/PSG/iot2000/linux-4.4-patches/0032-random-try-to-actively-add-entropy-rather-than-passi.patch
  34. 90 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0001-stmmac-pci-Make-stmmac_pci_info-structure-constant.patch
  35. 95 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0002-stmmac-pci-Use-stmmac_pci_info-for-all-devices.patch
  36. 61 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0003-stmmac-pci-Make-stmmac_pci_find_phy_addr-truly-gener.patch
  37. 165 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0004-stmmac-pci-Select-quark_pci_dmi_data-from-quark_defa.patch
  38. 167 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0005-stmmac-pci-Use-dmi_system_id-table-for-retrieving-PH.patch
  39. 47 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0006-stmmac-pci-Adjust-IOT2000-matching.patch
  40. 44 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0007-serial-8250_exar-Adjust-IOT2000-matching.patch
  41. 45 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0008-mfd-intel_quark_i2c_gpio-Adjust-IOT2000-matching.patch
  42. 86 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0009-gpio-sch-use-gpiochip-data-pointer.patch
  43. 46 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0010-gpio-sch-Use-devm_gpiochip_add_data-for-gpio-registr.patch
  44. 114 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0011-gpio-sch-Fix-Oops-on-module-load-on-Asus-Eee-PC-1201.patch
  45. 45 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0012-gpio-sch-Implement-.get_direction.patch
  46. 230 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0013-gpio-sch-Add-interrupt-support.patch
  47. 44 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0014-iot2000-hack-Work-around-DSDT-mistake.patch
  48. 42 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0015-iot2000-hack-Adjust-pca9685-gpio-base-for-legacy-com.patch
  49. 99 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0016-iot2000-hack-gpio-pca953x-provide-GPIO-base-based-on.patch
  50. 334 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0017-iot2000-hack-gpio-pca953x-add-drive-property.patch
  51. 105 0
      board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0018-iot2000-hack-pwm-pca-9685-Provide-chip-level-pwm_per.patch
  52. BIN
      board/PSG/iot2000/rootfs_overlay/lib/libsnap7.so
  53. 1 1
      configs/iot2000_defconfig
  54. 6 0
      package/Snap7/Config.in
  55. 24 0
      package/Snap7/Snap7.mk
  56. 98 0
      patches/007-modifications-CrossCompile-Toolchain.patch

+ 1 - 0
Config.in

@@ -6,3 +6,4 @@ source "$BR2_EXTERNAL_PSG_IOT2000_PATH/package/galileogen2-fake/Config.in"
 source "$BR2_EXTERNAL_PSG_IOT2000_PATH/package/adc1x8s102/Config.in"
 source "$BR2_EXTERNAL_PSG_IOT2000_PATH/package/icinga2/Config.in"
 source "$BR2_EXTERNAL_PSG_IOT2000_PATH/package/python-ufw/Config.in"
+source "$BR2_EXTERNAL_PSG_IOT2000_PATH/package/Snap7/Config.in"

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0001-stmmac-pci-Make-stmmac_pci_info-structure-constant.patch

@@ -1,7 +1,7 @@
-From 2ca48f47b659edbd5cf4c4e55c420ef40712ce9b Mon Sep 17 00:00:00 2001
+From 9d215622c3277114820de51365109896e0337ab8 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 22 Jun 2017 08:17:57 +0200
-Subject: [PATCH 01/18] stmmac: pci: Make stmmac_pci_info structure constant
+Subject: [PATCH 01/32] stmmac: pci: Make stmmac_pci_info structure constant
 
 Commit c5d5287ef0f763e836bf94659b3a6080358373f1 upstream.
 

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0002-stmmac-pci-Use-stmmac_pci_info-for-all-devices.patch

@@ -1,7 +1,7 @@
-From 5222a576c02eed33b0499a7e632a56680742a885 Mon Sep 17 00:00:00 2001
+From 94eff655c67ea28f35715f8864f3412faa2d827e Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 22 Jun 2017 08:17:58 +0200
-Subject: [PATCH 02/18] stmmac: pci: Use stmmac_pci_info for all devices
+Subject: [PATCH 02/32] stmmac: pci: Use stmmac_pci_info for all devices
 
 Commit b6a4c8f013ea2dd1ead7ee14b44712189a7bc6c6 upstream.
 

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0003-stmmac-pci-Make-stmmac_pci_find_phy_addr-truly-gener.patch

@@ -1,7 +1,7 @@
-From d9478f26f2c620cf284f5022d3d852c47227e8da Mon Sep 17 00:00:00 2001
+From 553355e45eac94312df999431b4491bb0dc43122 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 22 Jun 2017 08:17:59 +0200
-Subject: [PATCH 03/18] stmmac: pci: Make stmmac_pci_find_phy_addr truly
+Subject: [PATCH 03/32] stmmac: pci: Make stmmac_pci_find_phy_addr truly
  generic
 
 Commit c5f657e49c878756f21349f9e4b0f1c9631d5352 upstream.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0004-stmmac-pci-Select-quark_pci_dmi_data-from-quark_defa.patch

@@ -1,7 +1,7 @@
-From 0747f34d4be27952be866461c97d386c29000817 Mon Sep 17 00:00:00 2001
+From 95e91552d7a7d0fd28afc42191d8be1c3096d6c2 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 22 Jun 2017 08:18:00 +0200
-Subject: [PATCH 04/18] stmmac: pci: Select quark_pci_dmi_data from
+Subject: [PATCH 04/32] stmmac: pci: Select quark_pci_dmi_data from
  quark_default_data
 
 Commit 7bc519b3ea04026877242328d2fe73cc8e6102bd upsteam.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0005-stmmac-pci-Use-dmi_system_id-table-for-retrieving-PH.patch

@@ -1,7 +1,7 @@
-From 1b2894107ad2d9de45402ecc4ffe14f075a08bbc Mon Sep 17 00:00:00 2001
+From d771759e71dfab46de09fc2efcd1282926a775b8 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 22 Jun 2017 08:18:01 +0200
-Subject: [PATCH 05/18] stmmac: pci: Use dmi_system_id table for retrieving PHY
+Subject: [PATCH 05/32] stmmac: pci: Use dmi_system_id table for retrieving PHY
  addresses
 
 Commit 8d78b69091845386b6096f3adae98f28b9bf96ed upstream.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0006-stmmac-pci-Adjust-IOT2000-matching.patch

@@ -1,7 +1,7 @@
-From e3ba8c4f83c6c206a20e4645a37612b1e10580c6 Mon Sep 17 00:00:00 2001
+From 81aabe391560f74d9dafc5b139b3b3c2e6de08df Mon Sep 17 00:00:00 2001
 From: Su Bao Cheng <baocheng.su@siemens.com>
 Date: Fri, 12 Oct 2018 15:08:11 +0200
-Subject: [PATCH 06/18] stmmac: pci: Adjust IOT2000 matching
+Subject: [PATCH 06/32] stmmac: pci: Adjust IOT2000 matching
 
 Since there are more IOT2040 variants with identical hardware but
 different asset tags, the asset tag matching should be adjusted to

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0007-serial-8250_exar-Adjust-IOT2000-matching.patch

@@ -1,7 +1,7 @@
-From df74e188ffc38176d4caba969e104d2ab2e4e609 Mon Sep 17 00:00:00 2001
+From 186847dd575416b337ae370b46744a163fcf31fc Mon Sep 17 00:00:00 2001
 From: Su Bao Cheng <baocheng.su@siemens.com>
 Date: Fri, 12 Oct 2018 15:12:37 +0200
-Subject: [PATCH 07/18] serial: 8250_exar: Adjust IOT2000 matching
+Subject: [PATCH 07/32] serial: 8250_exar: Adjust IOT2000 matching
 
 Since there are more IOT2040 variants with identical hardware but
 different asset tags, the asset tag matching should be adjusted to

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0008-mfd-intel_quark_i2c_gpio-Adjust-IOT2000-matching.patch

@@ -1,7 +1,7 @@
-From 6e378b789ebcfcdc4ae957b25f1ac6eb2ef64edc Mon Sep 17 00:00:00 2001
+From f95eb6b146bc6107b082c8d600ac5ae51c05054e Mon Sep 17 00:00:00 2001
 From: Su Bao Cheng <baocheng.su@siemens.com>
 Date: Fri, 12 Oct 2018 15:05:07 +0200
-Subject: [PATCH 08/18] mfd: intel_quark_i2c_gpio: Adjust IOT2000 matching
+Subject: [PATCH 08/32] mfd: intel_quark_i2c_gpio: Adjust IOT2000 matching
 
 Since there are more IOT2040 variants with identical hardware but
 different asset tags, the asset tag matching should be adjusted to

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0009-gpio-sch-use-gpiochip-data-pointer.patch

@@ -1,7 +1,7 @@
-From cf3d1330c71d47c4cdb9268f68d2ee5931890d93 Mon Sep 17 00:00:00 2001
+From 31273219d4787459eea40094ac811a24cf20eaf6 Mon Sep 17 00:00:00 2001
 From: Linus Walleij <linus.walleij@linaro.org>
 Date: Mon, 7 Dec 2015 14:21:49 +0100
-Subject: [PATCH 09/18] gpio: sch: use gpiochip data pointer
+Subject: [PATCH 09/32] gpio: sch: use gpiochip data pointer
 
 This makes the driver use the data pointer added to the gpio_chip
 to store a pointer to the state container instead of relying on

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0010-gpio-sch-Use-devm_gpiochip_add_data-for-gpio-registr.patch

@@ -1,7 +1,7 @@
-From 6a930e4d040061edcaf0c3e3e43a10acdc20f09c Mon Sep 17 00:00:00 2001
+From 01837820d1cc75845d0c771f24eea5fe3d4ae109 Mon Sep 17 00:00:00 2001
 From: Laxman Dewangan <ldewangan@nvidia.com>
 Date: Mon, 22 Feb 2016 17:43:28 +0530
-Subject: [PATCH 10/18] gpio: sch: Use devm_gpiochip_add_data() for gpio
+Subject: [PATCH 10/32] gpio: sch: Use devm_gpiochip_add_data() for gpio
  registration
 
 Use devm_gpiochip_add_data() for GPIO registration and remove the

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0011-gpio-sch-Fix-Oops-on-module-load-on-Asus-Eee-PC-1201.patch

@@ -1,7 +1,7 @@
-From 9fd1991d762b6092f462f3cc551b2d7df3009b52 Mon Sep 17 00:00:00 2001
+From 3ecc35879dfd4a4df2ae418892743446fe05f3a0 Mon Sep 17 00:00:00 2001
 From: Colin Pitrat <colin.pitrat@gmail.com>
 Date: Sat, 18 Jun 2016 19:05:04 +0100
-Subject: [PATCH 11/18] gpio: sch: Fix Oops on module load on Asus Eee PC 1201
+Subject: [PATCH 11/32] gpio: sch: Fix Oops on module load on Asus Eee PC 1201
 
 This fixes the issue descirbe in bug 117531
 (https://bugzilla.kernel.org/show_bug.cgi?id=117531).

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0012-gpio-sch-Implement-.get_direction.patch

@@ -1,7 +1,7 @@
-From 8fec046f568e2b946abd55a82d5417717a115b21 Mon Sep 17 00:00:00 2001
+From 8c5cc2a98dcbcbd4208c62e5709d3669405072f7 Mon Sep 17 00:00:00 2001
 From: Linus Walleij <linus.walleij@linaro.org>
 Date: Wed, 27 Jun 2018 10:39:31 +0200
-Subject: [PATCH 12/18] gpio: sch: Implement .get_direction()
+Subject: [PATCH 12/32] gpio: sch: Implement .get_direction()
 
 It's pretty simple to implement the .get_direction() for this
 chip, so let's just do it.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0013-gpio-sch-Add-interrupt-support.patch

@@ -1,7 +1,7 @@
-From 53c90b014f54743b5a2180f90b90b1f198535583 Mon Sep 17 00:00:00 2001
+From d046375f1bc2a63d945bad8c4026ce1a6eabd838 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Wed, 17 Apr 2019 22:26:22 +0200
-Subject: [PATCH 13/18] gpio: sch: Add interrupt support
+Subject: [PATCH 13/32] gpio: sch: Add interrupt support
 
 Validated on the Quark platform, this adds interrupt support on rising
 and/or falling edges.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0014-iot2000-hack-Work-around-DSDT-mistake.patch

@@ -1,7 +1,7 @@
-From f43a54ec8a8b5f070d4b1b59f3d47dc03f74ad32 Mon Sep 17 00:00:00 2001
+From 63e4ba1816a80a258e4c7a846b3bd389b9a04e32 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 25 May 2017 11:09:42 +0200
-Subject: [PATCH 14/18] iot2000-hack: Work around DSDT mistake
+Subject: [PATCH 14/32] iot2000-hack: Work around DSDT mistake
 
 Until we have a new firmware revision, fix up the incorrect GPIO
 interrupt pin in software.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0015-iot2000-hack-Adjust-pca9685-gpio-base-for-legacy-com.patch

@@ -1,7 +1,7 @@
-From 88f2d0ccdee1f1890af0d049c60fe24f6c6eb048 Mon Sep 17 00:00:00 2001
+From e679338fe980d8722246366906bf71971fa2f538 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Thu, 25 May 2017 13:05:12 +0200
-Subject: [PATCH 15/18] iot2000-hack: Adjust pca9685-gpio base for legacy
+Subject: [PATCH 15/32] iot2000-hack: Adjust pca9685-gpio base for legacy
  compatibility
 
 mraa and the Arduino runtime expect this.

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0016-iot2000-hack-gpio-pca953x-provide-GPIO-base-based-on.patch

@@ -1,7 +1,7 @@
-From 5c102aea3f4ffea811eec719edd638fc7888e9c3 Mon Sep 17 00:00:00 2001
+From b4513d4a15616321e240c93436e8ffd58aa931ed Mon Sep 17 00:00:00 2001
 From: Yong Li <sdliyong@gmail.com>
 Date: Thu, 31 Mar 2016 15:33:08 +0800
-Subject: [PATCH 16/18] iot2000-hack: gpio: pca953x: provide GPIO base based on
+Subject: [PATCH 16/32] iot2000-hack: gpio: pca953x: provide GPIO base based on
  _UID
 
 Custom kernel for Intel Galileo Gen2 provides and moreover libmraa relies on

+ 6 - 6
board/PSG/iot2000/linux-4.4-patches/0017-iot2000-hack-gpio-pca953x-add-drive-property.patch

@@ -1,7 +1,7 @@
-From a66a980a3520859c1a01fc65f76c4f2abd2a2eed Mon Sep 17 00:00:00 2001
+From 7190fa3b9d76d0d554dab7c0a220a2be3e866560 Mon Sep 17 00:00:00 2001
 From: Yong Li <sdliyong@gmail.com>
 Date: Thu, 31 Mar 2016 15:33:09 +0800
-Subject: [PATCH 17/18] iot2000-hack: gpio-pca953x: add "drive" property
+Subject: [PATCH 17/32] iot2000-hack: gpio-pca953x: add "drive" property
 
 Galileo gen 2 has support for setting GPIO modes. Expose these
 properties through the GPIO sysfs interface. This approach is bit hacky,
@@ -201,10 +201,10 @@ index b57ed8e55ab5..72a8647146fa 100644
  };
  
 diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
-index 827510dbba30..d19928b9a311 100644
+index d72218fcaeeb..66d4e4a59035 100644
 --- a/drivers/gpio/gpiolib.c
 +++ b/drivers/gpio/gpiolib.c
-@@ -1315,6 +1315,23 @@ int gpiod_is_active_low(const struct gpio_desc *desc)
+@@ -1376,6 +1376,23 @@ int gpiod_is_active_low(const struct gpio_desc *desc)
  }
  EXPORT_SYMBOL_GPL(gpiod_is_active_low);
  
@@ -260,7 +260,7 @@ index 40ec1433f05d..519e8d458878 100644
  {
  	return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
 diff --git a/include/linux/gpio.h b/include/linux/gpio.h
-index d12b5d566e4b..344e62d27700 100644
+index 11555bd821b7..1e8ab82f2787 100644
 --- a/include/linux/gpio.h
 +++ b/include/linux/gpio.h
 @@ -30,6 +30,11 @@
@@ -317,7 +317,7 @@ index fb0fde686cb1..17f5f187699b 100644
  {
  	/* GPIO can never have been requested */
 diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
-index de502c7e4171..d59080ba9fec 100644
+index c0fc8effdba9..b73af28ac7d8 100644
 --- a/include/linux/gpio/driver.h
 +++ b/include/linux/gpio/driver.h
 @@ -116,6 +116,8 @@ struct gpio_chip {

+ 2 - 2
board/PSG/iot2000/linux-4.4-patches/0018-iot2000-hack-pwm-pca-9685-Provide-chip-level-pwm_per.patch

@@ -1,7 +1,7 @@
-From c25a8e605bcbb0ed2adde384587ffcfcf5783eef Mon Sep 17 00:00:00 2001
+From 0bdd0c91036a0c6a1cb74eebc3a95e08faf9e7b8 Mon Sep 17 00:00:00 2001
 From: Jan Kiszka <jan.kiszka@siemens.com>
 Date: Fri, 17 Nov 2017 20:25:54 +0100
-Subject: [PATCH 18/18] iot2000-hack: pwm: pca-9685: Provide chip-level
+Subject: [PATCH 18/32] iot2000-hack: pwm: pca-9685: Provide chip-level
  pwm_period attribute
 
 Arduino runtime relies on this path to program the PWM period, rather

+ 801 - 0
board/PSG/iot2000/linux-4.4-patches/0019-random-replace-non-blocking-pool-with-a-Chacha20-bas.patch

@@ -0,0 +1,801 @@
+From af72f4e73aa5a951d998e88260154082c5ffd340 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sun, 12 Jun 2016 18:13:36 -0400
+Subject: [PATCH 19/32] random: replace non-blocking pool with a Chacha20-based
+ CRNG
+
+The CRNG is faster, and we don't pretend to track entropy usage in the
+CRNG any more.
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ crypto/chacha20_generic.c |  61 --------
+ drivers/char/random.c     | 378 +++++++++++++++++++++++++++++++++-------------
+ include/crypto/chacha20.h |   1 +
+ lib/Makefile              |   2 +-
+ lib/chacha20.c            |  79 ++++++++++
+ 5 files changed, 357 insertions(+), 164 deletions(-)
+ create mode 100644 lib/chacha20.c
+
+diff --git a/crypto/chacha20_generic.c b/crypto/chacha20_generic.c
+index da9c89968223..1cab83146e33 100644
+--- a/crypto/chacha20_generic.c
++++ b/crypto/chacha20_generic.c
+@@ -15,72 +15,11 @@
+ #include <linux/module.h>
+ #include <crypto/chacha20.h>
+ 
+-static inline u32 rotl32(u32 v, u8 n)
+-{
+-	return (v << n) | (v >> (sizeof(v) * 8 - n));
+-}
+-
+ static inline u32 le32_to_cpuvp(const void *p)
+ {
+ 	return le32_to_cpup(p);
+ }
+ 
+-static void chacha20_block(u32 *state, void *stream)
+-{
+-	u32 x[16], *out = stream;
+-	int i;
+-
+-	for (i = 0; i < ARRAY_SIZE(x); i++)
+-		x[i] = state[i];
+-
+-	for (i = 0; i < 20; i += 2) {
+-		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],  16);
+-		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],  16);
+-		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],  16);
+-		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],  16);
+-
+-		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],  12);
+-		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],  12);
+-		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10], 12);
+-		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11], 12);
+-
+-		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],   8);
+-		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],   8);
+-		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],   8);
+-		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],   8);
+-
+-		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],   7);
+-		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],   7);
+-		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10],  7);
+-		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11],  7);
+-
+-		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],  16);
+-		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],  16);
+-		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],  16);
+-		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],  16);
+-
+-		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10], 12);
+-		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11], 12);
+-		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],  12);
+-		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],  12);
+-
+-		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],   8);
+-		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],   8);
+-		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],   8);
+-		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],   8);
+-
+-		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10],  7);
+-		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11],  7);
+-		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],   7);
+-		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],   7);
+-	}
+-
+-	for (i = 0; i < ARRAY_SIZE(x); i++)
+-		out[i] = cpu_to_le32(x[i] + state[i]);
+-
+-	state[12]++;
+-}
+-
+ static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src,
+ 			     unsigned int bytes)
+ {
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 2916d08ee30e..6d2abeae9434 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -260,6 +260,7 @@
+ #include <linux/irq.h>
+ #include <linux/syscalls.h>
+ #include <linux/completion.h>
++#include <crypto/chacha20.h>
+ 
+ #include <asm/processor.h>
+ #include <asm/uaccess.h>
+@@ -412,6 +413,31 @@ static struct fasync_struct *fasync;
+ static DEFINE_SPINLOCK(random_ready_list_lock);
+ static LIST_HEAD(random_ready_list);
+ 
++struct crng_state {
++	__u32		state[16];
++	unsigned long	init_time;
++	spinlock_t	lock;
++};
++
++struct crng_state primary_crng = {
++	.lock = __SPIN_LOCK_UNLOCKED(primary_crng.lock),
++};
++
++/*
++ * crng_init =  0 --> Uninitialized
++ *		1 --> Initialized
++ *		2 --> Initialized from input_pool
++ *
++ * crng_init is protected by primary_crng->lock, and only increases
++ * its value (from 0->1->2).
++ */
++static int crng_init = 0;
++#define crng_ready() (likely(crng_init > 0))
++static int crng_init_cnt = 0;
++#define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
++static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]);
++static void process_random_ready_list(void);
++
+ /**********************************************************************
+  *
+  * OS independent entropy store.   Here are the functions which handle
+@@ -441,10 +467,15 @@ struct entropy_store {
+ 	__u8 last_data[EXTRACT_SIZE];
+ };
+ 
++static ssize_t extract_entropy(struct entropy_store *r, void *buf,
++			       size_t nbytes, int min, int rsvd);
++static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
++				size_t nbytes, int fips);
++
++static void crng_reseed(struct crng_state *crng, struct entropy_store *r);
+ static void push_to_pool(struct work_struct *work);
+ static __u32 input_pool_data[INPUT_POOL_WORDS];
+ static __u32 blocking_pool_data[OUTPUT_POOL_WORDS];
+-static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS];
+ 
+ static struct entropy_store input_pool = {
+ 	.poolinfo = &poolinfo_table[0],
+@@ -465,16 +496,6 @@ static struct entropy_store blocking_pool = {
+ 					push_to_pool),
+ };
+ 
+-static struct entropy_store nonblocking_pool = {
+-	.poolinfo = &poolinfo_table[1],
+-	.name = "nonblocking",
+-	.pull = &input_pool,
+-	.lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock),
+-	.pool = nonblocking_pool_data,
+-	.push_work = __WORK_INITIALIZER(nonblocking_pool.push_work,
+-					push_to_pool),
+-};
+-
+ static __u32 const twist_table[8] = {
+ 	0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 	0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+@@ -677,12 +698,6 @@ retry:
+ 	if (!r->initialized && r->entropy_total > 128) {
+ 		r->initialized = 1;
+ 		r->entropy_total = 0;
+-		if (r == &nonblocking_pool) {
+-			prandom_reseed_late();
+-			process_random_ready_list();
+-			wake_up_all(&urandom_init_wait);
+-			pr_notice("random: %s pool is initialized\n", r->name);
+-		}
+ 	}
+ 
+ 	trace_credit_entropy_bits(r->name, nbits,
+@@ -692,30 +707,27 @@ retry:
+ 	if (r == &input_pool) {
+ 		int entropy_bits = entropy_count >> ENTROPY_SHIFT;
+ 
++		if (crng_init < 2 && entropy_bits >= 128) {
++			crng_reseed(&primary_crng, r);
++			entropy_bits = r->entropy_count >> ENTROPY_SHIFT;
++		}
++
+ 		/* should we wake readers? */
+ 		if (entropy_bits >= random_read_wakeup_bits) {
+ 			wake_up_interruptible(&random_read_wait);
+ 			kill_fasync(&fasync, SIGIO, POLL_IN);
+ 		}
+ 		/* If the input pool is getting full, send some
+-		 * entropy to the two output pools, flipping back and
+-		 * forth between them, until the output pools are 75%
+-		 * full.
++		 * entropy to the blocking pool until it is 75% full.
+ 		 */
+ 		if (entropy_bits > random_write_wakeup_bits &&
+ 		    r->initialized &&
+ 		    r->entropy_total >= 2*random_read_wakeup_bits) {
+-			static struct entropy_store *last = &blocking_pool;
+ 			struct entropy_store *other = &blocking_pool;
+ 
+-			if (last == &blocking_pool)
+-				other = &nonblocking_pool;
+ 			if (other->entropy_count <=
+-			    3 * other->poolinfo->poolfracbits / 4)
+-				last = other;
+-			if (last->entropy_count <=
+-			    3 * last->poolinfo->poolfracbits / 4) {
+-				schedule_work(&last->push_work);
++			    3 * other->poolinfo->poolfracbits / 4) {
++				schedule_work(&other->push_work);
+ 				r->entropy_total = 0;
+ 			}
+ 		}
+@@ -736,6 +748,152 @@ static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
+ 	return 0;
+ }
+ 
++/*********************************************************************
++ *
++ * CRNG using CHACHA20
++ *
++ *********************************************************************/
++
++#define CRNG_RESEED_INTERVAL (300*HZ)
++
++static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
++
++static void crng_initialize(struct crng_state *crng)
++{
++	int		i;
++	unsigned long	rv;
++
++	memcpy(&crng->state[0], "expand 32-byte k", 16);
++	if (crng == &primary_crng)
++		_extract_entropy(&input_pool, &crng->state[4],
++				 sizeof(__u32) * 12, 0);
++	else
++		get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
++	for (i = 4; i < 16; i++) {
++		if (!arch_get_random_seed_long(&rv) &&
++		    !arch_get_random_long(&rv))
++			rv = random_get_entropy();
++		crng->state[i] ^= rv;
++	}
++	crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
++}
++
++static int crng_fast_load(const char *cp, size_t len)
++{
++	unsigned long flags;
++	char *p;
++
++	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
++		return 0;
++	if (crng_ready()) {
++		spin_unlock_irqrestore(&primary_crng.lock, flags);
++		return 0;
++	}
++	p = (unsigned char *) &primary_crng.state[4];
++	while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) {
++		p[crng_init_cnt % CHACHA20_KEY_SIZE] ^= *cp;
++		cp++; crng_init_cnt++; len--;
++	}
++	if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
++		crng_init = 1;
++		wake_up_interruptible(&crng_init_wait);
++		pr_notice("random: fast init done\n");
++	}
++	spin_unlock_irqrestore(&primary_crng.lock, flags);
++	return 1;
++}
++
++static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
++{
++	unsigned long	flags;
++	int		i, num;
++	union {
++		__u8	block[CHACHA20_BLOCK_SIZE];
++		__u32	key[8];
++	} buf;
++
++	if (r) {
++		num = extract_entropy(r, &buf, 32, 16, 0);
++		if (num == 0)
++			return;
++	} else
++		extract_crng(buf.block);
++	spin_lock_irqsave(&primary_crng.lock, flags);
++	for (i = 0; i < 8; i++) {
++		unsigned long	rv;
++		if (!arch_get_random_seed_long(&rv) &&
++		    !arch_get_random_long(&rv))
++			rv = random_get_entropy();
++		crng->state[i+4] ^= buf.key[i] ^ rv;
++	}
++	memzero_explicit(&buf, sizeof(buf));
++	crng->init_time = jiffies;
++	if (crng == &primary_crng && crng_init < 2) {
++		crng_init = 2;
++		process_random_ready_list();
++		wake_up_interruptible(&crng_init_wait);
++		pr_notice("random: crng init done\n");
++	}
++	spin_unlock_irqrestore(&primary_crng.lock, flags);
++}
++
++static inline void crng_wait_ready(void)
++{
++	wait_event_interruptible(crng_init_wait, crng_ready());
++}
++
++static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
++{
++	unsigned long v, flags;
++	struct crng_state *crng = &primary_crng;
++
++	if (crng_init > 1 &&
++	    time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
++		crng_reseed(crng, &input_pool);
++	spin_lock_irqsave(&crng->lock, flags);
++	if (arch_get_random_long(&v))
++		crng->state[14] ^= v;
++	chacha20_block(&crng->state[0], out);
++	if (crng->state[12] == 0)
++		crng->state[13]++;
++	spin_unlock_irqrestore(&crng->lock, flags);
++}
++
++static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
++{
++	ssize_t ret = 0, i;
++	__u8 tmp[CHACHA20_BLOCK_SIZE];
++	int large_request = (nbytes > 256);
++
++	while (nbytes) {
++		if (large_request && need_resched()) {
++			if (signal_pending(current)) {
++				if (ret == 0)
++					ret = -ERESTARTSYS;
++				break;
++			}
++			schedule();
++		}
++
++		extract_crng(tmp);
++		i = min_t(int, nbytes, CHACHA20_BLOCK_SIZE);
++		if (copy_to_user(buf, tmp, i)) {
++			ret = -EFAULT;
++			break;
++		}
++
++		nbytes -= i;
++		buf += i;
++		ret += i;
++	}
++
++	/* Wipe data just written to memory */
++	memzero_explicit(tmp, sizeof(tmp));
++
++	return ret;
++}
++
++
+ /*********************************************************************
+  *
+  * Entropy input management
+@@ -752,12 +910,12 @@ struct timer_rand_state {
+ #define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, };
+ 
+ /*
+- * Add device- or boot-specific data to the input and nonblocking
+- * pools to help initialize them to unique values.
++ * Add device- or boot-specific data to the input pool to help
++ * initialize it.
+  *
+- * None of this adds any entropy, it is meant to avoid the
+- * problem of the nonblocking pool having similar initial state
+- * across largely identical devices.
++ * None of this adds any entropy; it is meant to avoid the problem of
++ * the entropy pool having similar initial state across largely
++ * identical devices.
+  */
+ void add_device_randomness(const void *buf, unsigned int size)
+ {
+@@ -769,11 +927,6 @@ void add_device_randomness(const void *buf, unsigned int size)
+ 	_mix_pool_bytes(&input_pool, buf, size);
+ 	_mix_pool_bytes(&input_pool, &time, sizeof(time));
+ 	spin_unlock_irqrestore(&input_pool.lock, flags);
+-
+-	spin_lock_irqsave(&nonblocking_pool.lock, flags);
+-	_mix_pool_bytes(&nonblocking_pool, buf, size);
+-	_mix_pool_bytes(&nonblocking_pool, &time, sizeof(time));
+-	spin_unlock_irqrestore(&nonblocking_pool.lock, flags);
+ }
+ EXPORT_SYMBOL(add_device_randomness);
+ 
+@@ -804,7 +957,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
+ 	sample.jiffies = jiffies;
+ 	sample.cycles = random_get_entropy();
+ 	sample.num = num;
+-	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
++	r = &input_pool;
+ 	mix_pool_bytes(r, &sample, sizeof(sample));
+ 
+ 	/*
+@@ -924,11 +1077,21 @@ void add_interrupt_randomness(int irq, int irq_flags)
+ 	fast_mix(fast_pool);
+ 	add_interrupt_bench(cycles);
+ 
++	if (!crng_ready()) {
++		if ((fast_pool->count >= 64) &&
++		    crng_fast_load((char *) fast_pool->pool,
++				   sizeof(fast_pool->pool))) {
++			fast_pool->count = 0;
++			fast_pool->last = now;
++		}
++		return;
++	}
++
+ 	if ((fast_pool->count < 64) &&
+ 	    !time_after(now, fast_pool->last + HZ))
+ 		return;
+ 
+-	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
++	r = &input_pool;
+ 	if (!spin_trylock(&r->lock))
+ 		return;
+ 
+@@ -972,9 +1135,6 @@ EXPORT_SYMBOL_GPL(add_disk_randomness);
+  *
+  *********************************************************************/
+ 
+-static ssize_t extract_entropy(struct entropy_store *r, void *buf,
+-			       size_t nbytes, int min, int rsvd);
+-
+ /*
+  * This utility inline function is responsible for transferring entropy
+  * from the primary pool to the secondary extraction pool. We make
+@@ -1149,6 +1309,36 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
+ 	memzero_explicit(&hash, sizeof(hash));
+ }
+ 
++static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
++				size_t nbytes, int fips)
++{
++	ssize_t ret = 0, i;
++	__u8 tmp[EXTRACT_SIZE];
++	unsigned long flags;
++
++	while (nbytes) {
++		extract_buf(r, tmp);
++
++		if (fips) {
++			spin_lock_irqsave(&r->lock, flags);
++			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
++				panic("Hardware RNG duplicated output!\n");
++			memcpy(r->last_data, tmp, EXTRACT_SIZE);
++			spin_unlock_irqrestore(&r->lock, flags);
++		}
++		i = min_t(int, nbytes, EXTRACT_SIZE);
++		memcpy(buf, tmp, i);
++		nbytes -= i;
++		buf += i;
++		ret += i;
++	}
++
++	/* Wipe data just returned from memory */
++	memzero_explicit(tmp, sizeof(tmp));
++
++	return ret;
++}
++
+ /*
+  * This function extracts randomness from the "entropy pool", and
+  * returns it in a buffer.
+@@ -1161,7 +1351,6 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
+ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
+ 				 size_t nbytes, int min, int reserved)
+ {
+-	ssize_t ret = 0, i;
+ 	__u8 tmp[EXTRACT_SIZE];
+ 	unsigned long flags;
+ 
+@@ -1185,27 +1374,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
+ 	xfer_secondary_pool(r, nbytes);
+ 	nbytes = account(r, nbytes, min, reserved);
+ 
+-	while (nbytes) {
+-		extract_buf(r, tmp);
+-
+-		if (fips_enabled) {
+-			spin_lock_irqsave(&r->lock, flags);
+-			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
+-				panic("Hardware RNG duplicated output!\n");
+-			memcpy(r->last_data, tmp, EXTRACT_SIZE);
+-			spin_unlock_irqrestore(&r->lock, flags);
+-		}
+-		i = min_t(int, nbytes, EXTRACT_SIZE);
+-		memcpy(buf, tmp, i);
+-		nbytes -= i;
+-		buf += i;
+-		ret += i;
+-	}
+-
+-	/* Wipe data just returned from memory */
+-	memzero_explicit(tmp, sizeof(tmp));
+-
+-	return ret;
++	return _extract_entropy(r, buf, nbytes, fips_enabled);
+ }
+ 
+ /*
+@@ -1260,15 +1429,26 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
+  */
+ void get_random_bytes(void *buf, int nbytes)
+ {
++	__u8 tmp[CHACHA20_BLOCK_SIZE];
++
+ #if DEBUG_RANDOM_BOOT > 0
+-	if (unlikely(nonblocking_pool.initialized == 0))
++	if (!crng_ready())
+ 		printk(KERN_NOTICE "random: %pF get_random_bytes called "
+-		       "with %d bits of entropy available\n",
+-		       (void *) _RET_IP_,
+-		       nonblocking_pool.entropy_total);
++		       "with crng_init = %d\n", (void *) _RET_IP_, crng_init);
+ #endif
+ 	trace_get_random_bytes(nbytes, _RET_IP_);
+-	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
++
++	while (nbytes >= CHACHA20_BLOCK_SIZE) {
++		extract_crng(buf);
++		buf += CHACHA20_BLOCK_SIZE;
++		nbytes -= CHACHA20_BLOCK_SIZE;
++	}
++
++	if (nbytes > 0) {
++		extract_crng(tmp);
++		memcpy(buf, tmp, nbytes);
++		memzero_explicit(tmp, nbytes);
++	}
+ }
+ EXPORT_SYMBOL(get_random_bytes);
+ 
+@@ -1286,7 +1466,7 @@ int add_random_ready_callback(struct random_ready_callback *rdy)
+ 	unsigned long flags;
+ 	int err = -EALREADY;
+ 
+-	if (likely(nonblocking_pool.initialized))
++	if (crng_ready())
+ 		return err;
+ 
+ 	owner = rdy->owner;
+@@ -1294,7 +1474,7 @@ int add_random_ready_callback(struct random_ready_callback *rdy)
+ 		return -ENOENT;
+ 
+ 	spin_lock_irqsave(&random_ready_list_lock, flags);
+-	if (nonblocking_pool.initialized)
++	if (crng_ready())
+ 		goto out;
+ 
+ 	owner = NULL;
+@@ -1358,7 +1538,7 @@ void get_random_bytes_arch(void *buf, int nbytes)
+ 	}
+ 
+ 	if (nbytes)
+-		extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
++		get_random_bytes(p, nbytes);
+ }
+ EXPORT_SYMBOL(get_random_bytes_arch);
+ 
+@@ -1403,7 +1583,7 @@ static int rand_initialize(void)
+ {
+ 	init_std_data(&input_pool);
+ 	init_std_data(&blocking_pool);
+-	init_std_data(&nonblocking_pool);
++	crng_initialize(&primary_crng);
+ 	return 0;
+ }
+ early_initcall(rand_initialize);
+@@ -1465,22 +1645,22 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+ static ssize_t
+ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+ {
++	unsigned long flags;
+ 	static int maxwarn = 10;
+ 	int ret;
+ 
+-	if (unlikely(nonblocking_pool.initialized == 0) &&
+-	    maxwarn > 0) {
++	if (!crng_ready() && maxwarn > 0) {
+ 		maxwarn--;
+ 		printk(KERN_NOTICE "random: %s: uninitialized urandom read "
+-		       "(%zd bytes read, %d bits of entropy available)\n",
+-		       current->comm, nbytes, nonblocking_pool.entropy_total);
++		       "(%zd bytes read)\n",
++		       current->comm, nbytes);
++		spin_lock_irqsave(&primary_crng.lock, flags);
++		crng_init_cnt = 0;
++		spin_unlock_irqrestore(&primary_crng.lock, flags);
+ 	}
+-
+ 	nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
+-	ret = extract_entropy_user(&nonblocking_pool, buf, nbytes);
+-
+-	trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool),
+-			   ENTROPY_BITS(&input_pool));
++	ret = extract_crng_user(buf, nbytes);
++	trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool));
+ 	return ret;
+ }
+ 
+@@ -1534,10 +1714,7 @@ static ssize_t random_write(struct file *file, const char __user *buffer,
+ {
+ 	size_t ret;
+ 
+-	ret = write_pool(&blocking_pool, buffer, count);
+-	if (ret)
+-		return ret;
+-	ret = write_pool(&nonblocking_pool, buffer, count);
++	ret = write_pool(&input_pool, buffer, count);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -1586,7 +1763,6 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
+ 		input_pool.entropy_count = 0;
+-		nonblocking_pool.entropy_count = 0;
+ 		blocking_pool.entropy_count = 0;
+ 		return 0;
+ 	default:
+@@ -1628,11 +1804,10 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+ 	if (flags & GRND_RANDOM)
+ 		return _random_read(flags & GRND_NONBLOCK, buf, count);
+ 
+-	if (unlikely(nonblocking_pool.initialized == 0)) {
++	if (!crng_ready()) {
+ 		if (flags & GRND_NONBLOCK)
+ 			return -EAGAIN;
+-		wait_event_interruptible(urandom_init_wait,
+-					 nonblocking_pool.initialized);
++		crng_wait_ready();
+ 		if (signal_pending(current))
+ 			return -ERESTARTSYS;
+ 	}
+@@ -1888,18 +2063,17 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
+ {
+ 	struct entropy_store *poolp = &input_pool;
+ 
+-	if (unlikely(nonblocking_pool.initialized == 0))
+-		poolp = &nonblocking_pool;
+-	else {
+-		/* Suspend writing if we're above the trickle
+-		 * threshold.  We'll be woken up again once below
+-		 * random_write_wakeup_thresh, or when the calling
+-		 * thread is about to terminate.
+-		 */
+-		wait_event_interruptible(random_write_wait,
+-					 kthread_should_stop() ||
+-			ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
++	if (!crng_ready()) {
++		crng_fast_load(buffer, count);
++		return;
+ 	}
++
++	/* Suspend writing if we're above the trickle threshold.
++	 * We'll be woken up again once below random_write_wakeup_thresh,
++	 * or when the calling thread is about to terminate.
++	 */
++	wait_event_interruptible(random_write_wait, kthread_should_stop() ||
++			ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
+ 	mix_pool_bytes(poolp, buffer, count);
+ 	credit_entropy_bits(poolp, entropy);
+ }
+diff --git a/include/crypto/chacha20.h b/include/crypto/chacha20.h
+index 274bbaeeed0f..20d20f681a72 100644
+--- a/include/crypto/chacha20.h
++++ b/include/crypto/chacha20.h
+@@ -16,6 +16,7 @@ struct chacha20_ctx {
+ 	u32 key[8];
+ };
+ 
++void chacha20_block(u32 *state, void *stream);
+ void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv);
+ int crypto_chacha20_setkey(struct crypto_tfm *tfm, const u8 *key,
+ 			   unsigned int keysize);
+diff --git a/lib/Makefile b/lib/Makefile
+index 34a7460c7005..c9ab674107ef 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -10,7 +10,7 @@ endif
+ lib-y := ctype.o string.o vsprintf.o cmdline.o \
+ 	 rbtree.o radix-tree.o dump_stack.o timerqueue.o\
+ 	 idr.o int_sqrt.o extable.o \
+-	 sha1.o md5.o irq_regs.o argv_split.o \
++	 sha1.o chacha20.o md5.o irq_regs.o argv_split.o \
+ 	 proportions.o flex_proportions.o ratelimit.o show_mem.o \
+ 	 is_single_threaded.o plist.o decompress.o kobject_uevent.o \
+ 	 earlycpio.o seq_buf.o siphash.o nmi_backtrace.o
+diff --git a/lib/chacha20.c b/lib/chacha20.c
+new file mode 100644
+index 000000000000..250ceed9ec9a
+--- /dev/null
++++ b/lib/chacha20.c
+@@ -0,0 +1,79 @@
++/*
++ * ChaCha20 256-bit cipher algorithm, RFC7539
++ *
++ * Copyright (C) 2015 Martin Willi
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/bitops.h>
++#include <linux/cryptohash.h>
++#include <asm/unaligned.h>
++#include <crypto/chacha20.h>
++
++static inline u32 rotl32(u32 v, u8 n)
++{
++	return (v << n) | (v >> (sizeof(v) * 8 - n));
++}
++
++extern void chacha20_block(u32 *state, void *stream)
++{
++	u32 x[16], *out = stream;
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(x); i++)
++		x[i] = state[i];
++
++	for (i = 0; i < 20; i += 2) {
++		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],  16);
++		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],  16);
++		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],  16);
++		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],  16);
++
++		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],  12);
++		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],  12);
++		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10], 12);
++		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11], 12);
++
++		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],   8);
++		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],   8);
++		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],   8);
++		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],   8);
++
++		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],   7);
++		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],   7);
++		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10],  7);
++		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11],  7);
++
++		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],  16);
++		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],  16);
++		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],  16);
++		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],  16);
++
++		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10], 12);
++		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11], 12);
++		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],  12);
++		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],  12);
++
++		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],   8);
++		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],   8);
++		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],   8);
++		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],   8);
++
++		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10],  7);
++		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11],  7);
++		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],   7);
++		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],   7);
++	}
++
++	for (i = 0; i < ARRAY_SIZE(x); i++)
++		out[i] = cpu_to_le32(x[i] + state[i]);
++
++	state[12]++;
++}
++EXPORT_SYMBOL(chacha20_block);
+-- 
+2.16.4
+

+ 143 - 0
board/PSG/iot2000/linux-4.4-patches/0020-random-make-dev-urandom-scalable-for-silly-userspace.patch

@@ -0,0 +1,143 @@
+From 90e62ff12f7205a70151ab1f45c437674a4fb81b Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Mon, 2 May 2016 02:04:41 -0400
+Subject: [PATCH 20/32] random: make /dev/urandom scalable for silly userspace
+ programs
+
+On a system with a 4 socket (NUMA) system where a large number of
+application threads were all trying to read from /dev/urandom, this
+can result in the system spending 80% of its time contending on the
+global urandom spinlock.  The application should have used its own
+PRNG, but let's try to help it from running, lemming-like, straight
+over the locking cliff.
+
+Reported-by: Andi Kleen <ak@linux.intel.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 58 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 6d2abeae9434..79b049e644f3 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -435,6 +435,8 @@ static int crng_init = 0;
+ #define crng_ready() (likely(crng_init > 0))
+ static int crng_init_cnt = 0;
+ #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
++static void _extract_crng(struct crng_state *crng,
++			  __u8 out[CHACHA20_BLOCK_SIZE]);
+ static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]);
+ static void process_random_ready_list(void);
+ 
+@@ -758,6 +760,16 @@ static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
+ 
++#ifdef CONFIG_NUMA
++/*
++ * Hack to deal with crazy userspace progams when they are all trying
++ * to access /dev/urandom in parallel.  The programs are almost
++ * certainly doing something terribly wrong, but we'll work around
++ * their brain damage.
++ */
++static struct crng_state **crng_node_pool __read_mostly;
++#endif
++
+ static void crng_initialize(struct crng_state *crng)
+ {
+ 	int		i;
+@@ -817,7 +829,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 		if (num == 0)
+ 			return;
+ 	} else
+-		extract_crng(buf.block);
++		_extract_crng(&primary_crng, buf.block);
+ 	spin_lock_irqsave(&primary_crng.lock, flags);
+ 	for (i = 0; i < 8; i++) {
+ 		unsigned long	rv;
+@@ -837,19 +849,26 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ }
+ 
++static inline void maybe_reseed_primary_crng(void)
++{
++	if (crng_init > 2 &&
++	    time_after(jiffies, primary_crng.init_time + CRNG_RESEED_INTERVAL))
++		crng_reseed(&primary_crng, &input_pool);
++}
++
+ static inline void crng_wait_ready(void)
+ {
+ 	wait_event_interruptible(crng_init_wait, crng_ready());
+ }
+ 
+-static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
++static void _extract_crng(struct crng_state *crng,
++			  __u8 out[CHACHA20_BLOCK_SIZE])
+ {
+ 	unsigned long v, flags;
+-	struct crng_state *crng = &primary_crng;
+ 
+ 	if (crng_init > 1 &&
+ 	    time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
+-		crng_reseed(crng, &input_pool);
++		crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
+ 	spin_lock_irqsave(&crng->lock, flags);
+ 	if (arch_get_random_long(&v))
+ 		crng->state[14] ^= v;
+@@ -859,6 +878,19 @@ static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
+ 	spin_unlock_irqrestore(&crng->lock, flags);
+ }
+ 
++static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
++{
++	struct crng_state *crng = NULL;
++
++#ifdef CONFIG_NUMA
++	if (crng_node_pool)
++		crng = crng_node_pool[numa_node_id()];
++	if (crng == NULL)
++#endif
++		crng = &primary_crng;
++	_extract_crng(crng, out);
++}
++
+ static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
+ {
+ 	ssize_t ret = 0, i;
+@@ -1581,9 +1613,31 @@ static void init_std_data(struct entropy_store *r)
+  */
+ static int rand_initialize(void)
+ {
++#ifdef CONFIG_NUMA
++	int i;
++	int num_nodes = num_possible_nodes();
++	struct crng_state *crng;
++	struct crng_state **pool;
++#endif
++
+ 	init_std_data(&input_pool);
+ 	init_std_data(&blocking_pool);
+ 	crng_initialize(&primary_crng);
++
++#ifdef CONFIG_NUMA
++	pool = kmalloc(num_nodes * sizeof(void *),
++		       GFP_KERNEL|__GFP_NOFAIL|__GFP_ZERO);
++	for (i=0; i < num_nodes; i++) {
++		crng = kmalloc_node(sizeof(struct crng_state),
++				    GFP_KERNEL | __GFP_NOFAIL, i);
++		spin_lock_init(&crng->lock);
++		crng_initialize(crng);
++		pool[i] = crng;
++
++	}
++	mb();
++	crng_node_pool = pool;
++#endif
+ 	return 0;
+ }
+ early_initcall(rand_initialize);
+-- 
+2.16.4
+

+ 109 - 0
board/PSG/iot2000/linux-4.4-patches/0021-random-add-backtracking-protection-to-the-CRNG.patch

@@ -0,0 +1,109 @@
+From a6d1adf3fed33218b5059d41128ab2b8b429d08c Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 4 May 2016 13:29:18 -0400
+Subject: [PATCH 21/32] random: add backtracking protection to the CRNG
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 49 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 79b049e644f3..a1214c0fbaf3 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -437,7 +437,8 @@ static int crng_init_cnt = 0;
+ #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
+ static void _extract_crng(struct crng_state *crng,
+ 			  __u8 out[CHACHA20_BLOCK_SIZE]);
+-static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]);
++static void _crng_backtrack_protect(struct crng_state *crng,
++				    __u8 tmp[CHACHA20_BLOCK_SIZE], int used);
+ static void process_random_ready_list(void);
+ 
+ /**********************************************************************
+@@ -828,8 +829,11 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 		num = extract_entropy(r, &buf, 32, 16, 0);
+ 		if (num == 0)
+ 			return;
+-	} else
++	} else {
+ 		_extract_crng(&primary_crng, buf.block);
++		_crng_backtrack_protect(&primary_crng, buf.block,
++					CHACHA20_KEY_SIZE);
++	}
+ 	spin_lock_irqsave(&primary_crng.lock, flags);
+ 	for (i = 0; i < 8; i++) {
+ 		unsigned long	rv;
+@@ -891,9 +895,46 @@ static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
+ 	_extract_crng(crng, out);
+ }
+ 
++/*
++ * Use the leftover bytes from the CRNG block output (if there is
++ * enough) to mutate the CRNG key to provide backtracking protection.
++ */
++static void _crng_backtrack_protect(struct crng_state *crng,
++				    __u8 tmp[CHACHA20_BLOCK_SIZE], int used)
++{
++	unsigned long	flags;
++	__u32		*s, *d;
++	int		i;
++
++	used = round_up(used, sizeof(__u32));
++	if (used + CHACHA20_KEY_SIZE > CHACHA20_BLOCK_SIZE) {
++		extract_crng(tmp);
++		used = 0;
++	}
++	spin_lock_irqsave(&crng->lock, flags);
++	s = (__u32 *) &tmp[used];
++	d = &crng->state[4];
++	for (i=0; i < 8; i++)
++		*d++ ^= *s++;
++	spin_unlock_irqrestore(&crng->lock, flags);
++}
++
++static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used)
++{
++	struct crng_state *crng = NULL;
++
++#ifdef CONFIG_NUMA
++	if (crng_node_pool)
++		crng = crng_node_pool[numa_node_id()];
++	if (crng == NULL)
++#endif
++		crng = &primary_crng;
++	_crng_backtrack_protect(crng, tmp, used);
++}
++
+ static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
+ {
+-	ssize_t ret = 0, i;
++	ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE;
+ 	__u8 tmp[CHACHA20_BLOCK_SIZE];
+ 	int large_request = (nbytes > 256);
+ 
+@@ -918,6 +959,7 @@ static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
+ 		buf += i;
+ 		ret += i;
+ 	}
++	crng_backtrack_protect(tmp, i);
+ 
+ 	/* Wipe data just written to memory */
+ 	memzero_explicit(tmp, sizeof(tmp));
+@@ -1479,8 +1521,10 @@ void get_random_bytes(void *buf, int nbytes)
+ 	if (nbytes > 0) {
+ 		extract_crng(tmp);
+ 		memcpy(buf, tmp, nbytes);
+-		memzero_explicit(tmp, nbytes);
+-	}
++		crng_backtrack_protect(tmp, nbytes);
++	} else
++		crng_backtrack_protect(tmp, CHACHA20_BLOCK_SIZE);
++	memzero_explicit(tmp, sizeof(tmp));
+ }
+ EXPORT_SYMBOL(get_random_bytes);
+ 
+-- 
+2.16.4
+

+ 35 - 0
board/PSG/iot2000/linux-4.4-patches/0022-random-remove-stale-maybe_reseed_primary_crng.patch

@@ -0,0 +1,35 @@
+From 1eadc614c3546b2cef698c337c95034253c99771 Mon Sep 17 00:00:00 2001
+From: Stephan Mueller <stephan.mueller@atsec.com>
+Date: Thu, 15 Dec 2016 12:42:33 +0100
+Subject: [PATCH 22/32] random: remove stale maybe_reseed_primary_crng
+
+The function maybe_reseed_primary_crng is not used anywhere and thus can
+be removed.
+
+Signed-off-by: Stephan Mueller <smueller@chronox.de>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index a1214c0fbaf3..a6a6a357ddae 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -853,13 +853,6 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ }
+ 
+-static inline void maybe_reseed_primary_crng(void)
+-{
+-	if (crng_init > 2 &&
+-	    time_after(jiffies, primary_crng.init_time + CRNG_RESEED_INTERVAL))
+-		crng_reseed(&primary_crng, &input_pool);
+-}
+-
+ static inline void crng_wait_ready(void)
+ {
+ 	wait_event_interruptible(crng_init_wait, crng_ready());
+-- 
+2.16.4
+

+ 180 - 0
board/PSG/iot2000/linux-4.4-patches/0023-random-use-chacha20-for-get_random_int-long.patch

@@ -0,0 +1,180 @@
+From b2a4ee8c97a7102789f81e428ce13d14a2ac1954 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 6 Jan 2017 19:32:01 +0100
+Subject: [PATCH 23/32] random: use chacha20 for get_random_int/long
+
+Now that our crng uses chacha20, we can rely on its speedy
+characteristics for replacing MD5, while simultaneously achieving a
+higher security guarantee. Before the idea was to use these functions if
+you wanted random integers that aren't stupidly insecure but aren't
+necessarily secure either, a vague gray zone, that hopefully was "good
+enough" for its users. With chacha20, we can strengthen this claim,
+since either we're using an rdrand-like instruction, or we're using the
+same crng as /dev/urandom. And it's faster than what was before.
+
+We could have chosen to replace this with a SipHash-derived function,
+which might be slightly faster, but at the cost of having yet another
+RNG construction in the kernel. By moving to chacha20, we have a single
+RNG to analyze and verify, and we also already get good performance
+improvements on all platforms.
+
+Implementation-wise, rather than use a generic buffer for both
+get_random_int/long and memcpy based on the size needs, we use a
+specific buffer for 32-bit reads and for 64-bit reads. This way, we're
+guaranteed to always have aligned accesses on all platforms. While
+slightly more verbose in C, the assembly this generates is a lot
+simpler than otherwise.
+
+Finally, on 32-bit platforms where longs and ints are the same size,
+we simply alias get_random_int to get_random_long.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Suggested-by: Theodore Ts'o <tytso@mit.edu>
+Cc: Theodore Ts'o <tytso@mit.edu>
+Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Cc: Andy Lutomirski <luto@amacapital.net>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c  | 84 ++++++++++++++++++++++++++------------------------
+ include/linux/random.h |  1 -
+ init/main.c            |  1 -
+ 3 files changed, 43 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index a6a6a357ddae..a10ff9c50cea 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -2068,63 +2068,65 @@ struct ctl_table random_table[] = {
+ };
+ #endif 	/* CONFIG_SYSCTL */
+ 
+-static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
+-
+-int random_int_secret_init(void)
+-{
+-	get_random_bytes(random_int_secret, sizeof(random_int_secret));
+-	return 0;
+-}
+-
+-static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash)
+-		__aligned(sizeof(unsigned long));
++struct batched_entropy {
++	union {
++		unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)];
++		unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)];
++	};
++	unsigned int position;
++};
+ 
+ /*
+- * Get a random word for internal kernel use only. Similar to urandom but
+- * with the goal of minimal entropy pool depletion. As a result, the random
+- * value is not cryptographically secure but for several uses the cost of
+- * depleting entropy is too high
++ * Get a random word for internal kernel use only. The quality of the random
++ * number is either as good as RDRAND or as good as /dev/urandom, with the
++ * goal of being quite fast and not depleting entropy.
+  */
+-unsigned int get_random_int(void)
++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long);
++unsigned long get_random_long(void)
+ {
+-	__u32 *hash;
+-	unsigned int ret;
++	unsigned long ret;
++	struct batched_entropy *batch;
+ 
+-	if (arch_get_random_int(&ret))
++	if (arch_get_random_long(&ret))
+ 		return ret;
+ 
+-	hash = get_cpu_var(get_random_int_hash);
+-
+-	hash[0] += current->pid + jiffies + random_get_entropy();
+-	md5_transform(hash, random_int_secret);
+-	ret = hash[0];
+-	put_cpu_var(get_random_int_hash);
+-
++	batch = &get_cpu_var(batched_entropy_long);
++	if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) {
++		extract_crng((u8 *)batch->entropy_long);
++		batch->position = 0;
++	}
++	ret = batch->entropy_long[batch->position++];
++	put_cpu_var(batched_entropy_long);
+ 	return ret;
+ }
+-EXPORT_SYMBOL(get_random_int);
++EXPORT_SYMBOL(get_random_long);
+ 
+-/*
+- * Same as get_random_int(), but returns unsigned long.
+- */
+-unsigned long get_random_long(void)
++#if BITS_PER_LONG == 32
++unsigned int get_random_int(void)
+ {
+-	__u32 *hash;
+-	unsigned long ret;
++	return get_random_long();
++}
++#else
++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int);
++unsigned int get_random_int(void)
++{
++	unsigned int ret;
++	struct batched_entropy *batch;
+ 
+-	if (arch_get_random_long(&ret))
++	if (arch_get_random_int(&ret))
+ 		return ret;
+ 
+-	hash = get_cpu_var(get_random_int_hash);
+-
+-	hash[0] += current->pid + jiffies + random_get_entropy();
+-	md5_transform(hash, random_int_secret);
+-	ret = *(unsigned long *)hash;
+-	put_cpu_var(get_random_int_hash);
+-
++	batch = &get_cpu_var(batched_entropy_int);
++	if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) {
++		extract_crng((u8 *)batch->entropy_int);
++		batch->position = 0;
++	}
++	ret = batch->entropy_int[batch->position++];
++	put_cpu_var(batched_entropy_int);
+ 	return ret;
+ }
+-EXPORT_SYMBOL(get_random_long);
++#endif
++EXPORT_SYMBOL(get_random_int);
+ 
+ /*
+  * randomize_range() returns a start address such that
+diff --git a/include/linux/random.h b/include/linux/random.h
+index 9c29122037f9..3e874bcdf8b8 100644
+--- a/include/linux/random.h
++++ b/include/linux/random.h
+@@ -27,7 +27,6 @@ extern int add_random_ready_callback(struct random_ready_callback *rdy);
+ extern void del_random_ready_callback(struct random_ready_callback *rdy);
+ extern void get_random_bytes_arch(void *buf, int nbytes);
+ void generate_random_uuid(unsigned char uuid_out[16]);
+-extern int random_int_secret_init(void);
+ 
+ #ifndef MODULE
+ extern const struct file_operations random_fops, urandom_fops;
+diff --git a/init/main.c b/init/main.c
+index e88c8cdef6a7..406cddf01de8 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -885,7 +885,6 @@ static void __init do_basic_setup(void)
+ 	do_ctors();
+ 	usermodehelper_enable();
+ 	do_initcalls();
+-	random_int_secret_init();
+ }
+ 
+ static void __init do_pre_smp_initcalls(void)
+-- 
+2.16.4
+

+ 147 - 0
board/PSG/iot2000/linux-4.4-patches/0024-random-convert-get_random_int-long-into-get_random_u.patch

@@ -0,0 +1,147 @@
+From 74f881a90ad219b51f59cc3ea700b3dd9decc2a3 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 22 Jan 2017 16:34:08 +0100
+Subject: [PATCH 24/32] random: convert get_random_int/long into
+ get_random_u32/u64
+
+Many times, when a user wants a random number, he wants a random number
+of a guaranteed size. So, thinking of get_random_int and get_random_long
+in terms of get_random_u32 and get_random_u64 makes it much easier to
+achieve this. It also makes the code simpler.
+
+On 32-bit platforms, get_random_int and get_random_long are both aliased
+to get_random_u32. On 64-bit platforms, int->u32 and long->u64.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c  | 55 +++++++++++++++++++++++++-------------------------
+ include/linux/random.h | 17 ++++++++++++++--
+ 2 files changed, 42 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index a10ff9c50cea..d79a631a2b5e 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -2070,8 +2070,8 @@ struct ctl_table random_table[] = {
+ 
+ struct batched_entropy {
+ 	union {
+-		unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)];
+-		unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)];
++		u64 entropy_u64[CHACHA20_BLOCK_SIZE / sizeof(u64)];
++		u32 entropy_u32[CHACHA20_BLOCK_SIZE / sizeof(u32)];
+ 	};
+ 	unsigned int position;
+ };
+@@ -2081,52 +2081,51 @@ struct batched_entropy {
+  * number is either as good as RDRAND or as good as /dev/urandom, with the
+  * goal of being quite fast and not depleting entropy.
+  */
+-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long);
+-unsigned long get_random_long(void)
++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
++u64 get_random_u64(void)
+ {
+-	unsigned long ret;
++	u64 ret;
+ 	struct batched_entropy *batch;
+ 
+-	if (arch_get_random_long(&ret))
++#if BITS_PER_LONG == 64
++	if (arch_get_random_long((unsigned long *)&ret))
+ 		return ret;
++#else
++	if (arch_get_random_long((unsigned long *)&ret) &&
++	    arch_get_random_long((unsigned long *)&ret + 1))
++	    return ret;
++#endif
+ 
+-	batch = &get_cpu_var(batched_entropy_long);
+-	if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) {
+-		extract_crng((u8 *)batch->entropy_long);
++	batch = &get_cpu_var(batched_entropy_u64);
++	if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
++		extract_crng((u8 *)batch->entropy_u64);
+ 		batch->position = 0;
+ 	}
+-	ret = batch->entropy_long[batch->position++];
+-	put_cpu_var(batched_entropy_long);
++	ret = batch->entropy_u64[batch->position++];
++	put_cpu_var(batched_entropy_u64);
+ 	return ret;
+ }
+-EXPORT_SYMBOL(get_random_long);
++EXPORT_SYMBOL(get_random_u64);
+ 
+-#if BITS_PER_LONG == 32
+-unsigned int get_random_int(void)
+-{
+-	return get_random_long();
+-}
+-#else
+-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int);
+-unsigned int get_random_int(void)
++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
++u32 get_random_u32(void)
+ {
+-	unsigned int ret;
++	u32 ret;
+ 	struct batched_entropy *batch;
+ 
+ 	if (arch_get_random_int(&ret))
+ 		return ret;
+ 
+-	batch = &get_cpu_var(batched_entropy_int);
+-	if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) {
+-		extract_crng((u8 *)batch->entropy_int);
++	batch = &get_cpu_var(batched_entropy_u32);
++	if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
++		extract_crng((u8 *)batch->entropy_u32);
+ 		batch->position = 0;
+ 	}
+-	ret = batch->entropy_int[batch->position++];
+-	put_cpu_var(batched_entropy_int);
++	ret = batch->entropy_u32[batch->position++];
++	put_cpu_var(batched_entropy_u32);
+ 	return ret;
+ }
+-#endif
+-EXPORT_SYMBOL(get_random_int);
++EXPORT_SYMBOL(get_random_u32);
+ 
+ /*
+  * randomize_range() returns a start address such that
+diff --git a/include/linux/random.h b/include/linux/random.h
+index 3e874bcdf8b8..39f125ba80bb 100644
+--- a/include/linux/random.h
++++ b/include/linux/random.h
+@@ -32,8 +32,21 @@ void generate_random_uuid(unsigned char uuid_out[16]);
+ extern const struct file_operations random_fops, urandom_fops;
+ #endif
+ 
+-unsigned int get_random_int(void);
+-unsigned long get_random_long(void);
++u32 get_random_u32(void);
++u64 get_random_u64(void);
++static inline unsigned int get_random_int(void)
++{
++	return get_random_u32();
++}
++static inline unsigned long get_random_long(void)
++{
++#if BITS_PER_LONG == 64
++	return get_random_u64();
++#else
++	return get_random_u32();
++#endif
++}
++
+ unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
+ 
+ u32 prandom_u32(void);
+-- 
+2.16.4
+

+ 148 - 0
board/PSG/iot2000/linux-4.4-patches/0025-random-invalidate-batched-entropy-after-crng-init.patch

@@ -0,0 +1,148 @@
+From a4829bebf0be947a5ec2880b15ec77d5178d6a17 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 7 Jun 2017 19:45:31 -0400
+Subject: [PATCH 25/32] random: invalidate batched entropy after crng init
+
+It's possible that get_random_{u32,u64} is used before the crng has
+initialized, in which case, its output might not be cryptographically
+secure. For this problem, directly, this patch set is introducing the
+*_wait variety of functions, but even with that, there's a subtle issue:
+what happens to our batched entropy that was generated before
+initialization. Prior to this commit, it'd stick around, supplying bad
+numbers. After this commit, we force the entropy to be re-extracted
+after each phase of the crng has initialized.
+
+In order to avoid a race condition with the position counter, we
+introduce a simple rwlock for this invalidation. Since it's only during
+this awkward transition period, after things are all set up, we stop
+using it, so that it doesn't have an impact on performance.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@vger.kernel.org  # v4.11+
+---
+ drivers/char/random.c | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index d79a631a2b5e..6c571ee0d6c4 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -1,6 +1,9 @@
+ /*
+  * random.c -- A strong random number generator
+  *
++ * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All
++ * Rights Reserved.
++ *
+  * Copyright Matt Mackall <mpm@selenic.com>, 2003, 2004, 2005
+  *
+  * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999.  All
+@@ -771,6 +774,8 @@ static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
+ static struct crng_state **crng_node_pool __read_mostly;
+ #endif
+ 
++static void invalidate_batched_entropy(void);
++
+ static void crng_initialize(struct crng_state *crng)
+ {
+ 	int		i;
+@@ -808,6 +813,7 @@ static int crng_fast_load(const char *cp, size_t len)
+ 		cp++; crng_init_cnt++; len--;
+ 	}
+ 	if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
++		invalidate_batched_entropy();
+ 		crng_init = 1;
+ 		wake_up_interruptible(&crng_init_wait);
+ 		pr_notice("random: fast init done\n");
+@@ -845,6 +851,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 	memzero_explicit(&buf, sizeof(buf));
+ 	crng->init_time = jiffies;
+ 	if (crng == &primary_crng && crng_init < 2) {
++		invalidate_batched_entropy();
+ 		crng_init = 2;
+ 		process_random_ready_list();
+ 		wake_up_interruptible(&crng_init_wait);
+@@ -2075,6 +2082,7 @@ struct batched_entropy {
+ 	};
+ 	unsigned int position;
+ };
++static rwlock_t batched_entropy_reset_lock = __RW_LOCK_UNLOCKED(batched_entropy_reset_lock);
+ 
+ /*
+  * Get a random word for internal kernel use only. The quality of the random
+@@ -2085,6 +2093,8 @@ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
+ u64 get_random_u64(void)
+ {
+ 	u64 ret;
++	bool use_lock = crng_init < 2;
++	unsigned long flags;
+ 	struct batched_entropy *batch;
+ 
+ #if BITS_PER_LONG == 64
+@@ -2097,11 +2107,15 @@ u64 get_random_u64(void)
+ #endif
+ 
+ 	batch = &get_cpu_var(batched_entropy_u64);
++	if (use_lock)
++		read_lock_irqsave(&batched_entropy_reset_lock, flags);
+ 	if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
+ 		extract_crng((u8 *)batch->entropy_u64);
+ 		batch->position = 0;
+ 	}
+ 	ret = batch->entropy_u64[batch->position++];
++	if (use_lock)
++		read_unlock_irqrestore(&batched_entropy_reset_lock, flags);
+ 	put_cpu_var(batched_entropy_u64);
+ 	return ret;
+ }
+@@ -2111,22 +2125,45 @@ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
+ u32 get_random_u32(void)
+ {
+ 	u32 ret;
++	bool use_lock = crng_init < 2;
++	unsigned long flags;
+ 	struct batched_entropy *batch;
+ 
+ 	if (arch_get_random_int(&ret))
+ 		return ret;
+ 
+ 	batch = &get_cpu_var(batched_entropy_u32);
++	if (use_lock)
++		read_lock_irqsave(&batched_entropy_reset_lock, flags);
+ 	if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
+ 		extract_crng((u8 *)batch->entropy_u32);
+ 		batch->position = 0;
+ 	}
+ 	ret = batch->entropy_u32[batch->position++];
++	if (use_lock)
++		read_unlock_irqrestore(&batched_entropy_reset_lock, flags);
+ 	put_cpu_var(batched_entropy_u32);
+ 	return ret;
+ }
+ EXPORT_SYMBOL(get_random_u32);
+ 
++/* It's important to invalidate all potential batched entropy that might
++ * be stored before the crng is initialized, which we can do lazily by
++ * simply resetting the counter to zero so that it's re-extracted on the
++ * next usage. */
++static void invalidate_batched_entropy(void)
++{
++	int cpu;
++	unsigned long flags;
++
++	write_lock_irqsave(&batched_entropy_reset_lock, flags);
++	for_each_possible_cpu (cpu) {
++		per_cpu_ptr(&batched_entropy_u32, cpu)->position = 0;
++		per_cpu_ptr(&batched_entropy_u64, cpu)->position = 0;
++	}
++	write_unlock_irqrestore(&batched_entropy_reset_lock, flags);
++}
++
+ /*
+  * randomize_range() returns a start address such that
+  *
+-- 
+2.16.4
+

+ 87 - 0
board/PSG/iot2000/linux-4.4-patches/0026-random-silence-compiler-warnings-and-fix-race.patch

@@ -0,0 +1,87 @@
+From 45cf6623ee8462c12e9a971620ea01fdae7b0114 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 15 Jun 2017 00:45:26 +0200
+Subject: [PATCH 26/32] random: silence compiler warnings and fix race
+
+Odd versions of gcc for the sh4 architecture will actually warn about
+flags being used while uninitialized, so we set them to zero. Non crazy
+gccs will optimize that out again, so it doesn't make a difference.
+
+Next, over aggressive gccs could inline the expression that defines
+use_lock, which could then introduce a race resulting in a lock
+imbalance. By using READ_ONCE, we prevent that fate. Finally, we make
+that assignment const, so that gcc can still optimize a nice amount.
+
+Finally, we fix a potential deadlock between primary_crng.lock and
+batched_entropy_reset_lock, where they could be called in opposite
+order. Moving the call to invalidate_batched_entropy to outside the lock
+rectifies this issue.
+
+Fixes: b169c13de473a85b3c859bb36216a4cb5f00a54a
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@vger.kernel.org
+---
+ drivers/char/random.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 6c571ee0d6c4..194cdb02d458 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -812,13 +812,13 @@ static int crng_fast_load(const char *cp, size_t len)
+ 		p[crng_init_cnt % CHACHA20_KEY_SIZE] ^= *cp;
+ 		cp++; crng_init_cnt++; len--;
+ 	}
++	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ 	if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
+ 		invalidate_batched_entropy();
+ 		crng_init = 1;
+ 		wake_up_interruptible(&crng_init_wait);
+ 		pr_notice("random: fast init done\n");
+ 	}
+-	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ 	return 1;
+ }
+ 
+@@ -850,6 +850,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 	}
+ 	memzero_explicit(&buf, sizeof(buf));
+ 	crng->init_time = jiffies;
++	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ 	if (crng == &primary_crng && crng_init < 2) {
+ 		invalidate_batched_entropy();
+ 		crng_init = 2;
+@@ -857,7 +858,6 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 		wake_up_interruptible(&crng_init_wait);
+ 		pr_notice("random: crng init done\n");
+ 	}
+-	spin_unlock_irqrestore(&primary_crng.lock, flags);
+ }
+ 
+ static inline void crng_wait_ready(void)
+@@ -2093,8 +2093,8 @@ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
+ u64 get_random_u64(void)
+ {
+ 	u64 ret;
+-	bool use_lock = crng_init < 2;
+-	unsigned long flags;
++	bool use_lock = READ_ONCE(crng_init) < 2;
++	unsigned long flags = 0;
+ 	struct batched_entropy *batch;
+ 
+ #if BITS_PER_LONG == 64
+@@ -2125,8 +2125,8 @@ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
+ u32 get_random_u32(void)
+ {
+ 	u32 ret;
+-	bool use_lock = crng_init < 2;
+-	unsigned long flags;
++	bool use_lock = READ_ONCE(crng_init) < 2;
++	unsigned long flags = 0;
+ 	struct batched_entropy *batch;
+ 
+ 	if (arch_get_random_int(&ret))
+-- 
+2.16.4
+

+ 118 - 0
board/PSG/iot2000/linux-4.4-patches/0027-random-add-wait_for_random_bytes-API.patch

@@ -0,0 +1,118 @@
+From bab97a70fbb2f35de923e07d1e2377ad43b024af Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 7 Jun 2017 19:58:56 -0400
+Subject: [PATCH 27/32] random: add wait_for_random_bytes() API
+
+This enables users of get_random_{bytes,u32,u64,int,long} to wait until
+the pool is ready before using this function, in case they actually want
+to have reliable randomness.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c  | 41 +++++++++++++++++++++++++++++++----------
+ include/linux/random.h |  1 +
+ 2 files changed, 32 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 194cdb02d458..198ae9df9d9e 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -860,11 +860,6 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ 	}
+ }
+ 
+-static inline void crng_wait_ready(void)
+-{
+-	wait_event_interruptible(crng_init_wait, crng_ready());
+-}
+-
+ static void _extract_crng(struct crng_state *crng,
+ 			  __u8 out[CHACHA20_BLOCK_SIZE])
+ {
+@@ -1499,7 +1494,10 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
+  * number of good random numbers, suitable for key generation, seeding
+  * TCP sequence numbers, etc.  It does not rely on the hardware random
+  * number generator.  For random bytes direct from the hardware RNG
+- * (when available), use get_random_bytes_arch().
++ * (when available), use get_random_bytes_arch(). In order to ensure
++ * that the randomness provided by this function is okay, the function
++ * wait_for_random_bytes() should be called and return 0 at least once
++ * at any point prior.
+  */
+ void get_random_bytes(void *buf, int nbytes)
+ {
+@@ -1528,6 +1526,24 @@ void get_random_bytes(void *buf, int nbytes)
+ }
+ EXPORT_SYMBOL(get_random_bytes);
+ 
++/*
++ * Wait for the urandom pool to be seeded and thus guaranteed to supply
++ * cryptographically secure random numbers. This applies to: the /dev/urandom
++ * device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
++ * family of functions. Using any of these functions without first calling
++ * this function forfeits the guarantee of security.
++ *
++ * Returns: 0 if the urandom pool has been seeded.
++ *          -ERESTARTSYS if the function was interrupted by a signal.
++ */
++int wait_for_random_bytes(void)
++{
++	if (likely(crng_ready()))
++		return 0;
++	return wait_event_interruptible(crng_init_wait, crng_ready());
++}
++EXPORT_SYMBOL(wait_for_random_bytes);
++
+ /*
+  * Add a callback function that will be invoked when the nonblocking
+  * pool is initialised.
+@@ -1893,6 +1909,8 @@ const struct file_operations urandom_fops = {
+ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+ 		unsigned int, flags)
+ {
++	int ret;
++
+ 	if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
+ 		return -EINVAL;
+ 
+@@ -1905,9 +1923,9 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+ 	if (!crng_ready()) {
+ 		if (flags & GRND_NONBLOCK)
+ 			return -EAGAIN;
+-		crng_wait_ready();
+-		if (signal_pending(current))
+-			return -ERESTARTSYS;
++		ret = wait_for_random_bytes();
++		if (unlikely(ret))
++			return ret;
+ 	}
+ 	return urandom_read(NULL, buf, count, NULL);
+ }
+@@ -2087,7 +2105,10 @@ static rwlock_t batched_entropy_reset_lock = __RW_LOCK_UNLOCKED(batched_entropy_
+ /*
+  * Get a random word for internal kernel use only. The quality of the random
+  * number is either as good as RDRAND or as good as /dev/urandom, with the
+- * goal of being quite fast and not depleting entropy.
++ * goal of being quite fast and not depleting entropy. In order to ensure
++ * that the randomness provided by this function is okay, the function
++ * wait_for_random_bytes() should be called and return 0 at least once
++ * at any point prior.
+  */
+ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
+ u64 get_random_u64(void)
+diff --git a/include/linux/random.h b/include/linux/random.h
+index 39f125ba80bb..b282d7adcacc 100644
+--- a/include/linux/random.h
++++ b/include/linux/random.h
+@@ -23,6 +23,7 @@ extern void add_input_randomness(unsigned int type, unsigned int code,
+ extern void add_interrupt_randomness(int irq, int irq_flags);
+ 
+ extern void get_random_bytes(void *buf, int nbytes);
++extern int wait_for_random_bytes(void);
+ extern int add_random_ready_callback(struct random_ready_callback *rdy);
+ extern void del_random_ready_callback(struct random_ready_callback *rdy);
+ extern void get_random_bytes_arch(void *buf, int nbytes);
+-- 
+2.16.4
+

+ 77 - 0
board/PSG/iot2000/linux-4.4-patches/0028-random-fix-crng_ready-test.patch

@@ -0,0 +1,77 @@
+From 24cef0dbc155391db6e2eceba26cba476e54dd15 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 11 Apr 2018 13:27:52 -0400
+Subject: [PATCH 28/32] random: fix crng_ready() test
+
+The crng_init variable has three states:
+
+0: The CRNG is not initialized at all
+1: The CRNG has a small amount of entropy, hopefully good enough for
+   early-boot, non-cryptographical use cases
+2: The CRNG is fully initialized and we are sure it is safe for
+   cryptographic use cases.
+
+The crng_ready() function should only return true once we are in the
+last state.  This addresses CVE-2018-1108.
+
+Reported-by: Jann Horn <jannh@google.com>
+Fixes: e192be9d9a30 ("random: replace non-blocking pool...")
+Cc: stable@kernel.org # 4.8+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Reviewed-by: Jann Horn <jannh@google.com>
+---
+ drivers/char/random.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 198ae9df9d9e..747b7d6d4f44 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -435,7 +435,7 @@ struct crng_state primary_crng = {
+  * its value (from 0->1->2).
+  */
+ static int crng_init = 0;
+-#define crng_ready() (likely(crng_init > 0))
++#define crng_ready() (likely(crng_init > 1))
+ static int crng_init_cnt = 0;
+ #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
+ static void _extract_crng(struct crng_state *crng,
+@@ -803,7 +803,7 @@ static int crng_fast_load(const char *cp, size_t len)
+ 
+ 	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
+ 		return 0;
+-	if (crng_ready()) {
++	if (crng_init != 0) {
+ 		spin_unlock_irqrestore(&primary_crng.lock, flags);
+ 		return 0;
+ 	}
+@@ -865,7 +865,7 @@ static void _extract_crng(struct crng_state *crng,
+ {
+ 	unsigned long v, flags;
+ 
+-	if (crng_init > 1 &&
++	if (crng_ready() &&
+ 	    time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
+ 		crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
+ 	spin_lock_irqsave(&crng->lock, flags);
+@@ -1146,7 +1146,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
+ 	fast_mix(fast_pool);
+ 	add_interrupt_bench(cycles);
+ 
+-	if (!crng_ready()) {
++	if (unlikely(crng_init == 0)) {
+ 		if ((fast_pool->count >= 64) &&
+ 		    crng_fast_load((char *) fast_pool->pool,
+ 				   sizeof(fast_pool->pool))) {
+@@ -2213,7 +2213,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
+ {
+ 	struct entropy_store *poolp = &input_pool;
+ 
+-	if (!crng_ready()) {
++	if (unlikely(crng_init == 0)) {
+ 		crng_fast_load(buffer, count);
+ 		return;
+ 	}
+-- 
+2.16.4
+

+ 110 - 0
board/PSG/iot2000/linux-4.4-patches/0029-random-use-a-different-mixing-algorithm-for-add_devi.patch

@@ -0,0 +1,110 @@
+From 0e756274490a989fc8a368d0072b20019a5bd53d Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 11 Apr 2018 14:58:27 -0400
+Subject: [PATCH 29/32] random: use a different mixing algorithm for
+ add_device_randomness()
+
+add_device_randomness() use of crng_fast_load() was highly
+problematic.  Some callers of add_device_randomness() can pass in a
+large amount of static information.  This would immediately promote
+the crng_init state from 0 to 1, without really doing much to
+initialize the primary_crng's internal state with something even
+vaguely unpredictable.
+
+Since we don't have the speed constraints of add_interrupt_randomness(),
+we can do a better job mixing in the what unpredictability a device
+driver or architecture maintainer might see fit to give us, and do it
+in a way which does not bump the crng_init_cnt variable.
+
+Also, since add_device_randomness() doesn't bump any entropy
+accounting in crng_init state 0, mix the device randomness into the
+input_pool entropy pool as well.  This is related to CVE-2018-1108.
+
+Reported-by: Jann Horn <jannh@google.com>
+Fixes: ee7998c50c26 ("random: do not ignore early device randomness")
+Cc: stable@kernel.org # 4.13+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 747b7d6d4f44..ca9127abad52 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -796,6 +796,10 @@ static void crng_initialize(struct crng_state *crng)
+ 	crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
+ }
+ 
++/*
++ * crng_fast_load() can be called by code in the interrupt service
++ * path.  So we can't afford to dilly-dally.
++ */
+ static int crng_fast_load(const char *cp, size_t len)
+ {
+ 	unsigned long flags;
+@@ -822,6 +826,51 @@ static int crng_fast_load(const char *cp, size_t len)
+ 	return 1;
+ }
+ 
++/*
++ * crng_slow_load() is called by add_device_randomness, which has two
++ * attributes.  (1) We can't trust the buffer passed to it is
++ * guaranteed to be unpredictable (so it might not have any entropy at
++ * all), and (2) it doesn't have the performance constraints of
++ * crng_fast_load().
++ *
++ * So we do something more comprehensive which is guaranteed to touch
++ * all of the primary_crng's state, and which uses a LFSR with a
++ * period of 255 as part of the mixing algorithm.  Finally, we do
++ * *not* advance crng_init_cnt since buffer we may get may be something
++ * like a fixed DMI table (for example), which might very well be
++ * unique to the machine, but is otherwise unvarying.
++ */
++static int crng_slow_load(const char *cp, size_t len)
++{
++	unsigned long		flags;
++	static unsigned char	lfsr = 1;
++	unsigned char		tmp;
++	unsigned		i, max = CHACHA20_KEY_SIZE;
++	const char *		src_buf = cp;
++	char *			dest_buf = (char *) &primary_crng.state[4];
++
++	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
++		return 0;
++	if (crng_init != 0) {
++		spin_unlock_irqrestore(&primary_crng.lock, flags);
++		return 0;
++	}
++	if (len > max)
++		max = len;
++
++	for (i = 0; i < max ; i++) {
++		tmp = lfsr;
++		lfsr >>= 1;
++		if (tmp & 1)
++			lfsr ^= 0xE1;
++		tmp = dest_buf[i % CHACHA20_KEY_SIZE];
++		dest_buf[i % CHACHA20_KEY_SIZE] ^= src_buf[i % len] ^ lfsr;
++		lfsr += (tmp << 3) | (tmp >> 5);
++	}
++	spin_unlock_irqrestore(&primary_crng.lock, flags);
++	return 1;
++}
++
+ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
+ {
+ 	unsigned long	flags;
+@@ -991,6 +1040,9 @@ void add_device_randomness(const void *buf, unsigned int size)
+ 	unsigned long time = random_get_entropy() ^ jiffies;
+ 	unsigned long flags;
+ 
++	if (!crng_ready() && size)
++		crng_slow_load(buf, size);
++
+ 	trace_add_device_randomness(size, _RET_IP_);
+ 	spin_lock_irqsave(&input_pool.lock, flags);
+ 	_mix_pool_bytes(&input_pool, buf, size);
+-- 
+2.16.4
+

+ 163 - 0
board/PSG/iot2000/linux-4.4-patches/0030-random-only-read-from-dev-random-after-its-pool-has-.patch

@@ -0,0 +1,163 @@
+From 6cb95e11da746d51f1defd91d5904f90c15fb743 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 20 Feb 2019 16:06:38 -0500
+Subject: [PATCH 30/32] random: only read from /dev/random after its pool has
+ received 128 bits
+
+Immediately after boot, we allow reads from /dev/random before its
+entropy pool has been fully initialized.  Fix this so that we don't
+allow this until the blocking pool has received 128 bits.
+
+We do this by repurposing the initialized flag in the entropy pool
+struct, and use the initialized flag in the blocking pool to indicate
+whether it is safe to pull from the blocking pool.
+
+To do this, we needed to rework when we decide to push entropy from the
+input pool to the blocking pool, since the initialized flag for the
+input pool was used for this purpose.  To simplify things, we no
+longer use the initialized flag for that purpose, nor do we use the
+entropy_total field any more.
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c         | 44 +++++++++++++++++++++----------------------
+ include/trace/events/random.h | 13 +++++--------
+ 2 files changed, 27 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index ca9127abad52..f37a90896821 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -466,7 +466,6 @@ struct entropy_store {
+ 	unsigned short add_ptr;
+ 	unsigned short input_rotate;
+ 	int entropy_count;
+-	int entropy_total;
+ 	unsigned int initialized:1;
+ 	unsigned int limit:1;
+ 	unsigned int last_data_init:1;
+@@ -642,7 +641,7 @@ static void process_random_ready_list(void)
+  */
+ static void credit_entropy_bits(struct entropy_store *r, int nbits)
+ {
+-	int entropy_count, orig;
++	int entropy_count, orig, has_initialized = 0;
+ 	const int pool_size = r->poolinfo->poolfracbits;
+ 	int nfrac = nbits << ENTROPY_SHIFT;
+ 
+@@ -697,23 +696,25 @@ retry:
+ 		entropy_count = 0;
+ 	} else if (entropy_count > pool_size)
+ 		entropy_count = pool_size;
++	if ((r == &blocking_pool) && !r->initialized &&
++	    (entropy_count >> ENTROPY_SHIFT) > 128)
++		has_initialized = 1;
+ 	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
+ 		goto retry;
+ 
+-	r->entropy_total += nbits;
+-	if (!r->initialized && r->entropy_total > 128) {
++	if (has_initialized)
+ 		r->initialized = 1;
+-		r->entropy_total = 0;
+-	}
+ 
+ 	trace_credit_entropy_bits(r->name, nbits,
+-				  entropy_count >> ENTROPY_SHIFT,
+-				  r->entropy_total, _RET_IP_);
++				  entropy_count >> ENTROPY_SHIFT, _RET_IP_);
+ 
+ 	if (r == &input_pool) {
+ 		int entropy_bits = entropy_count >> ENTROPY_SHIFT;
++		struct entropy_store *other = &blocking_pool;
+ 
+-		if (crng_init < 2 && entropy_bits >= 128) {
++		if (crng_init < 2) {
++			if (entropy_bits < 128)
++				return;
+ 			crng_reseed(&primary_crng, r);
+ 			entropy_bits = r->entropy_count >> ENTROPY_SHIFT;
+ 		}
+@@ -723,20 +724,14 @@ retry:
+ 			wake_up_interruptible(&random_read_wait);
+ 			kill_fasync(&fasync, SIGIO, POLL_IN);
+ 		}
+-		/* If the input pool is getting full, send some
+-		 * entropy to the blocking pool until it is 75% full.
++		/* If the input pool is getting full, and the blocking
++		 * pool has room, send some entropy to the blocking
++		 * pool.
+ 		 */
+-		if (entropy_bits > random_write_wakeup_bits &&
+-		    r->initialized &&
+-		    r->entropy_total >= 2*random_read_wakeup_bits) {
+-			struct entropy_store *other = &blocking_pool;
+-
+-			if (other->entropy_count <=
+-			    3 * other->poolinfo->poolfracbits / 4) {
+-				schedule_work(&other->push_work);
+-				r->entropy_total = 0;
+-			}
+-		}
++		if (!work_pending(&other->push_work) &&
++		    (ENTROPY_BITS(r) > 6 * r->poolinfo->poolbytes) &&
++		    (ENTROPY_BITS(other) <= 6 * other->poolinfo->poolbytes))
++			schedule_work(&other->push_work);
+ 	}
+ }
+ 
+@@ -1510,6 +1505,11 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
+ 	int large_request = (nbytes > 256);
+ 
+ 	trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
++	if (!r->initialized && r->pull) {
++		xfer_secondary_pool(r, ENTROPY_BITS(r->pull)/8);
++		if (!r->initialized)
++			return 0;
++	}
+ 	xfer_secondary_pool(r, nbytes);
+ 	nbytes = account(r, nbytes, 0, 0);
+ 
+diff --git a/include/trace/events/random.h b/include/trace/events/random.h
+index 4684de344c5d..d5323630be90 100644
+--- a/include/trace/events/random.h
++++ b/include/trace/events/random.h
+@@ -61,15 +61,14 @@ DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes_nolock,
+ 
+ TRACE_EVENT(credit_entropy_bits,
+ 	TP_PROTO(const char *pool_name, int bits, int entropy_count,
+-		 int entropy_total, unsigned long IP),
++		 unsigned long IP),
+ 
+-	TP_ARGS(pool_name, bits, entropy_count, entropy_total, IP),
++	TP_ARGS(pool_name, bits, entropy_count, IP),
+ 
+ 	TP_STRUCT__entry(
+ 		__field( const char *,	pool_name		)
+ 		__field(	  int,	bits			)
+ 		__field(	  int,	entropy_count		)
+-		__field(	  int,	entropy_total		)
+ 		__field(unsigned long,	IP			)
+ 	),
+ 
+@@ -77,14 +76,12 @@ TRACE_EVENT(credit_entropy_bits,
+ 		__entry->pool_name	= pool_name;
+ 		__entry->bits		= bits;
+ 		__entry->entropy_count	= entropy_count;
+-		__entry->entropy_total	= entropy_total;
+ 		__entry->IP		= IP;
+ 	),
+ 
+-	TP_printk("%s pool: bits %d entropy_count %d entropy_total %d "
+-		  "caller %pS", __entry->pool_name, __entry->bits,
+-		  __entry->entropy_count, __entry->entropy_total,
+-		  (void *)__entry->IP)
++	TP_printk("%s pool: bits %d entropy_count %d caller %pS",
++		  __entry->pool_name, __entry->bits,
++		  __entry->entropy_count, (void *)__entry->IP)
+ );
+ 
+ TRACE_EVENT(push_to_pool,
+-- 
+2.16.4
+

+ 58 - 0
board/PSG/iot2000/linux-4.4-patches/0031-random-fix-soft-lockup-when-trying-to-read-from-an-u.patch

@@ -0,0 +1,58 @@
+From 4fe896ddf122abf98234154db65773db70f0b8a1 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 22 May 2019 12:02:16 -0400
+Subject: [PATCH 31/32] random: fix soft lockup when trying to read from an
+ uninitialized blocking pool
+
+Fixes: eb9d1bf079bb: "random: only read from /dev/random after its pool has received 128 bits"
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ drivers/char/random.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index f37a90896821..29755924aa45 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -702,8 +702,11 @@ retry:
+ 	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
+ 		goto retry;
+ 
+-	if (has_initialized)
++	if (has_initialized) {
+ 		r->initialized = 1;
++		wake_up_interruptible(&random_read_wait);
++		kill_fasync(&fasync, SIGIO, POLL_IN);
++	}
+ 
+ 	trace_credit_entropy_bits(r->name, nbits,
+ 				  entropy_count >> ENTROPY_SHIFT, _RET_IP_);
+@@ -719,6 +722,13 @@ retry:
+ 			entropy_bits = r->entropy_count >> ENTROPY_SHIFT;
+ 		}
+ 
++		/* initialize the blocking pool if necessary */
++		if (entropy_bits >= random_read_wakeup_bits &&
++		    !other->initialized) {
++			schedule_work(&other->push_work);
++			return;
++		}
++
+ 		/* should we wake readers? */
+ 		if (entropy_bits >= random_read_wakeup_bits) {
+ 			wake_up_interruptible(&random_read_wait);
+@@ -1795,8 +1805,8 @@ _random_read(int nonblock, char __user *buf, size_t nbytes)
+ 			return -EAGAIN;
+ 
+ 		wait_event_interruptible(random_read_wait,
+-			ENTROPY_BITS(&input_pool) >=
+-			random_read_wakeup_bits);
++		    blocking_pool.initialized &&
++		    (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits));
+ 		if (signal_pending(current))
+ 			return -ERESTARTSYS;
+ 	}
+-- 
+2.16.4
+

+ 145 - 0
board/PSG/iot2000/linux-4.4-patches/0032-random-try-to-actively-add-entropy-rather-than-passi.patch

@@ -0,0 +1,145 @@
+From eb0b7b33a7bb77cd54cc4627044a77f1ee002139 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Sat, 28 Sep 2019 16:53:52 -0700
+Subject: [PATCH 32/32] random: try to actively add entropy rather than
+ passively wait for it
+
+For 5.3 we had to revert a nice ext4 IO pattern improvement, because it
+caused a bootup regression due to lack of entropy at bootup together
+with arguably broken user space that was asking for secure random
+numbers when it really didn't need to.
+
+See commit 72dbcf721566 (Revert "ext4: make __ext4_get_inode_loc plug").
+
+This aims to solve the issue by actively generating entropy noise using
+the CPU cycle counter when waiting for the random number generator to
+initialize.  This only works when you have a high-frequency time stamp
+counter available, but that's the case on all modern x86 CPU's, and on
+most other modern CPU's too.
+
+What we do is to generate jitter entropy from the CPU cycle counter
+under a somewhat complex load: calling the scheduler while also
+guaranteeing a certain amount of timing noise by also triggering a
+timer.
+
+I'm sure we can tweak this, and that people will want to look at other
+alternatives, but there's been a number of papers written on jitter
+entropy, and this should really be fairly conservative by crediting one
+bit of entropy for every timer-induced jump in the cycle counter.  Not
+because the timer itself would be all that unpredictable, but because
+the interaction between the timer and the loop is going to be.
+
+Even if (and perhaps particularly if) the timer actually happens on
+another CPU, the cacheline interaction between the loop that reads the
+cycle counter and the timer itself firing is going to add perturbations
+to the cycle counter values that get mixed into the entropy pool.
+
+As Thomas pointed out, with a modern out-of-order CPU, even quite simple
+loops show a fair amount of hard-to-predict timing variability even in
+the absense of external interrupts.  But this tries to take that further
+by actually having a fairly complex interaction.
+
+This is not going to solve the entropy issue for architectures that have
+no CPU cycle counter, but it's not clear how (and if) that is solvable,
+and the hardware in question is largely starting to be irrelevant.  And
+by doing this we can at least avoid some of the even more contentious
+approaches (like making the entropy waiting time out in order to avoid
+the possibly unbounded waiting).
+
+Cc: Ahmed Darwish <darwish.07@gmail.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Theodore Ts'o <tytso@mit.edu>
+Cc: Nicholas Mc Guire <hofrat@opentech.at>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Willy Tarreau <w@1wt.eu>
+Cc: Alexander E. Patrakov <patrakov@gmail.com>
+Cc: Lennart Poettering <mzxreary@0pointer.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ drivers/char/random.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 61 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 29755924aa45..8bded70230de 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -1588,6 +1588,56 @@ void get_random_bytes(void *buf, int nbytes)
+ }
+ EXPORT_SYMBOL(get_random_bytes);
+ 
++
++/*
++ * Each time the timer fires, we expect that we got an unpredictable
++ * jump in the cycle counter. Even if the timer is running on another
++ * CPU, the timer activity will be touching the stack of the CPU that is
++ * generating entropy..
++ *
++ * Note that we don't re-arm the timer in the timer itself - we are
++ * happy to be scheduled away, since that just makes the load more
++ * complex, but we do not want the timer to keep ticking unless the
++ * entropy loop is running.
++ *
++ * So the re-arming always happens in the entropy loop itself.
++ */
++static void entropy_timer(unsigned long unused)
++{
++	credit_entropy_bits(&input_pool, 1);
++}
++
++/*
++ * If we have an actual cycle counter, see if we can
++ * generate enough entropy with timing noise
++ */
++static void try_to_generate_entropy(void)
++{
++	struct {
++		unsigned long now;
++		struct timer_list timer;
++	} stack;
++
++	stack.now = random_get_entropy();
++
++	/* Slow counter - or none. Don't even bother */
++	if (stack.now == random_get_entropy())
++		return;
++
++	setup_timer_on_stack(&stack.timer, entropy_timer, 0);
++	while (!crng_ready()) {
++		if (!timer_pending(&stack.timer))
++			mod_timer(&stack.timer, jiffies+1);
++		mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
++		schedule();
++		stack.now = random_get_entropy();
++	}
++
++	del_timer_sync(&stack.timer);
++	destroy_timer_on_stack(&stack.timer);
++	mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
++}
++
+ /*
+  * Wait for the urandom pool to be seeded and thus guaranteed to supply
+  * cryptographically secure random numbers. This applies to: the /dev/urandom
+@@ -1602,7 +1652,17 @@ int wait_for_random_bytes(void)
+ {
+ 	if (likely(crng_ready()))
+ 		return 0;
+-	return wait_event_interruptible(crng_init_wait, crng_ready());
++
++	do {
++		int ret;
++		ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
++		if (ret)
++			return ret > 0 ? 0 : ret;
++
++		try_to_generate_entropy();
++	} while (!crng_ready());
++
++	return 0;
+ }
+ EXPORT_SYMBOL(wait_for_random_bytes);
+ 
+-- 
+2.16.4
+

+ 90 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0001-stmmac-pci-Make-stmmac_pci_info-structure-constant.patch

@@ -0,0 +1,90 @@
+From 2ca48f47b659edbd5cf4c4e55c420ef40712ce9b Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 22 Jun 2017 08:17:57 +0200
+Subject: [PATCH 01/18] stmmac: pci: Make stmmac_pci_info structure constant
+
+Commit c5d5287ef0f763e836bf94659b3a6080358373f1 upstream.
+
+By removing the PCI device reference from the structure and passing it
+as parameters to the interested functions, we can make quark_pci_info
+const.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 3491e98bffc5..828d276748e3 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -42,17 +42,17 @@ struct stmmac_pci_dmi_data {
+ };
+ 
+ struct stmmac_pci_info {
+-	struct pci_dev *pdev;
+-	int (*setup)(struct plat_stmmacenet_data *plat,
+-		     struct stmmac_pci_info *info);
++	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat,
++		     const struct stmmac_pci_info *info);
+ 	struct stmmac_pci_dmi_data *dmi;
+ };
+ 
+-static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
++static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
++				    const struct stmmac_pci_info *info)
+ {
+ 	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
+ 	const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG);
+-	unsigned int func = PCI_FUNC(info->pdev->devfn);
++	unsigned int func = PCI_FUNC(pdev->devfn);
+ 	struct stmmac_pci_dmi_data *dmi;
+ 
+ 	/*
+@@ -96,17 +96,17 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
+ 	plat->unicast_filter_entries = 1;
+ }
+ 
+-static int quark_default_data(struct plat_stmmacenet_data *plat,
+-			      struct stmmac_pci_info *info)
++static int quark_default_data(struct pci_dev *pdev,
++			      struct plat_stmmacenet_data *plat,
++			      const struct stmmac_pci_info *info)
+ {
+-	struct pci_dev *pdev = info->pdev;
+ 	int ret;
+ 
+ 	/*
+ 	 * Refuse to load the driver and register net device if MAC controller
+ 	 * does not connect to any PHY interface.
+ 	 */
+-	ret = stmmac_pci_find_phy_addr(info);
++	ret = stmmac_pci_find_phy_addr(pdev, info);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -165,7 +165,7 @@ static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
+ 	{}
+ };
+ 
+-static struct stmmac_pci_info quark_pci_info = {
++static const struct stmmac_pci_info quark_pci_info = {
+ 	.setup = quark_default_data,
+ 	.dmi = quark_pci_dmi_data,
+ };
+@@ -227,9 +227,8 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ 	pci_set_master(pdev);
+ 
+ 	if (info) {
+-		info->pdev = pdev;
+ 		if (info->setup) {
+-			ret = info->setup(plat, info);
++			ret = info->setup(pdev, plat, info);
+ 			if (ret)
+ 				return ret;
+ 		}
+-- 
+2.16.4
+

+ 95 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0002-stmmac-pci-Use-stmmac_pci_info-for-all-devices.patch

@@ -0,0 +1,95 @@
+From 5222a576c02eed33b0499a7e632a56680742a885 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 22 Jun 2017 08:17:58 +0200
+Subject: [PATCH 02/18] stmmac: pci: Use stmmac_pci_info for all devices
+
+Commit b6a4c8f013ea2dd1ead7ee14b44712189a7bc6c6 upstream.
+
+Make stmmac_default_data compatible with stmmac_pci_info.setup and use
+an info structure for all devices. This allows to make the probing more
+regular.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 36 +++++++++++++++---------
+ 1 file changed, 23 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 828d276748e3..a60059032dc6 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -74,7 +74,9 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+ 	return -ENODEV;
+ }
+ 
+-static void stmmac_default_data(struct plat_stmmacenet_data *plat)
++static int stmmac_default_data(struct pci_dev *pdev,
++			       struct plat_stmmacenet_data *plat,
++			       const struct stmmac_pci_info *info)
+ {
+ 	plat->bus_id = 1;
+ 	plat->phy_addr = 0;
+@@ -94,8 +96,14 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
+ 
+ 	/* Set default value for unicast filter entries */
+ 	plat->unicast_filter_entries = 1;
++
++	return 0;
+ }
+ 
++static const struct stmmac_pci_info stmmac_pci_info = {
++	.setup = stmmac_default_data,
++};
++
+ static int quark_default_data(struct pci_dev *pdev,
+ 			      struct plat_stmmacenet_data *plat,
+ 			      const struct stmmac_pci_info *info)
+@@ -226,14 +234,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ 
+ 	pci_set_master(pdev);
+ 
+-	if (info) {
+-		if (info->setup) {
+-			ret = info->setup(pdev, plat, info);
+-			if (ret)
+-				return ret;
+-		}
+-	} else
+-		stmmac_default_data(plat);
++	ret = info->setup(pdev, plat, info);
++	if (ret)
++		return ret;
+ 
+ 	pci_enable_msi(pdev);
+ 
+@@ -279,14 +282,21 @@ static int stmmac_pci_resume(struct device *dev)
+ 
+ static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
+ 
+-#define STMMAC_VENDOR_ID 0x700
++/* synthetic ID, no official vendor */
++#define PCI_VENDOR_ID_STMMAC 0x700
++
+ #define STMMAC_QUARK_ID  0x0937
+ #define STMMAC_DEVICE_ID 0x1108
+ 
++#define STMMAC_DEVICE(vendor_id, dev_id, info)	{	\
++	PCI_VDEVICE(vendor_id, dev_id),			\
++	.driver_data = (kernel_ulong_t)&info		\
++	}
++
+ static const struct pci_device_id stmmac_id_table[] = {
+-	{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
+-	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
+-	{PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info},
++	STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info),
++	STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info),
++	STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info),
+ 	{}
+ };
+ 
+-- 
+2.16.4
+

+ 61 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0003-stmmac-pci-Make-stmmac_pci_find_phy_addr-truly-gener.patch

@@ -0,0 +1,61 @@
+From d9478f26f2c620cf284f5022d3d852c47227e8da Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 22 Jun 2017 08:17:59 +0200
+Subject: [PATCH 03/18] stmmac: pci: Make stmmac_pci_find_phy_addr truly
+ generic
+
+Commit c5f657e49c878756f21349f9e4b0f1c9631d5352 upstream.
+
+Move the special case for the early Galileo firmware into
+quark_default_setup. This allows to use stmmac_pci_find_phy_addr for
+non-quark cases.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index a60059032dc6..19cf9607618a 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -55,12 +55,8 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+ 	unsigned int func = PCI_FUNC(pdev->devfn);
+ 	struct stmmac_pci_dmi_data *dmi;
+ 
+-	/*
+-	 * Galileo boards with old firmware don't support DMI. We always return
+-	 * 1 here, so at least first found MAC controller would be probed.
+-	 */
+ 	if (!name)
+-		return 1;
++		return -ENODEV;
+ 
+ 	for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
+ 		if (!strcmp(dmi->name, name) && dmi->func == func) {
+@@ -115,8 +111,18 @@ static int quark_default_data(struct pci_dev *pdev,
+ 	 * does not connect to any PHY interface.
+ 	 */
+ 	ret = stmmac_pci_find_phy_addr(pdev, info);
+-	if (ret < 0)
+-		return ret;
++	if (ret < 0) {
++		/* Return error to the caller on DMI enabled boards. */
++		if (dmi_get_system_info(DMI_BOARD_NAME))
++			return ret;
++
++		/*
++		 * Galileo boards with old firmware don't support DMI. We always
++		 * use 1 here as PHY address, so at least the first found MAC
++		 * controller would be probed.
++		 */
++		ret = 1;
++	}
+ 
+ 	plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+ 	plat->phy_addr = ret;
+-- 
+2.16.4
+

+ 165 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0004-stmmac-pci-Select-quark_pci_dmi_data-from-quark_defa.patch

@@ -0,0 +1,165 @@
+From 0747f34d4be27952be866461c97d386c29000817 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 22 Jun 2017 08:18:00 +0200
+Subject: [PATCH 04/18] stmmac: pci: Select quark_pci_dmi_data from
+ quark_default_data
+
+Commit 7bc519b3ea04026877242328d2fe73cc8e6102bd upsteam.
+
+No need to carry this reference in stmmac_pci_info - the Quark-specific
+setup handler knows that it needs to use the Quark-specific DMI table.
+This also allows to drop the stmmac_pci_info reference from the setup
+handler parameter list.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 83 +++++++++++-------------
+ 1 file changed, 39 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 19cf9607618a..9fe6368738ec 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -42,13 +42,11 @@ struct stmmac_pci_dmi_data {
+ };
+ 
+ struct stmmac_pci_info {
+-	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat,
+-		     const struct stmmac_pci_info *info);
+-	struct stmmac_pci_dmi_data *dmi;
++	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
+ };
+ 
+ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+-				    const struct stmmac_pci_info *info)
++				    struct stmmac_pci_dmi_data *dmi_data)
+ {
+ 	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
+ 	const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG);
+@@ -58,7 +56,7 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+ 	if (!name)
+ 		return -ENODEV;
+ 
+-	for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
++	for (dmi = dmi_data; dmi->name && *dmi->name; dmi++) {
+ 		if (!strcmp(dmi->name, name) && dmi->func == func) {
+ 			/* If asset tag is provided, match on it as well. */
+ 			if (dmi->asset_tag && strcmp(dmi->asset_tag, asset_tag))
+@@ -71,8 +69,7 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+ }
+ 
+ static int stmmac_default_data(struct pci_dev *pdev,
+-			       struct plat_stmmacenet_data *plat,
+-			       const struct stmmac_pci_info *info)
++			       struct plat_stmmacenet_data *plat)
+ {
+ 	plat->bus_id = 1;
+ 	plat->phy_addr = 0;
+@@ -100,9 +97,40 @@ static const struct stmmac_pci_info stmmac_pci_info = {
+ 	.setup = stmmac_default_data,
+ };
+ 
++static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
++	{
++		.name = "Galileo",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{
++		.name = "GalileoGen2",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{
++		.name = "SIMATIC IOT2000",
++		.asset_tag = "6ES7647-0AA00-0YA2",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{
++		.name = "SIMATIC IOT2000",
++		.asset_tag = "6ES7647-0AA00-1YA2",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{
++		.name = "SIMATIC IOT2000",
++		.asset_tag = "6ES7647-0AA00-1YA2",
++		.func = 7,
++		.phy_addr = 1,
++	},
++	{}
++};
++
+ static int quark_default_data(struct pci_dev *pdev,
+-			      struct plat_stmmacenet_data *plat,
+-			      const struct stmmac_pci_info *info)
++			      struct plat_stmmacenet_data *plat)
+ {
+ 	int ret;
+ 
+@@ -110,7 +138,7 @@ static int quark_default_data(struct pci_dev *pdev,
+ 	 * Refuse to load the driver and register net device if MAC controller
+ 	 * does not connect to any PHY interface.
+ 	 */
+-	ret = stmmac_pci_find_phy_addr(pdev, info);
++	ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi_data);
+ 	if (ret < 0) {
+ 		/* Return error to the caller on DMI enabled boards. */
+ 		if (dmi_get_system_info(DMI_BOARD_NAME))
+@@ -147,41 +175,8 @@ static int quark_default_data(struct pci_dev *pdev,
+ 	return 0;
+ }
+ 
+-static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
+-	{
+-		.name = "Galileo",
+-		.func = 6,
+-		.phy_addr = 1,
+-	},
+-	{
+-		.name = "GalileoGen2",
+-		.func = 6,
+-		.phy_addr = 1,
+-	},
+-	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-0YA2",
+-		.func = 6,
+-		.phy_addr = 1,
+-	},
+-	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-1YA2",
+-		.func = 6,
+-		.phy_addr = 1,
+-	},
+-	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-1YA2",
+-		.func = 7,
+-		.phy_addr = 1,
+-	},
+-	{}
+-};
+-
+ static const struct stmmac_pci_info quark_pci_info = {
+ 	.setup = quark_default_data,
+-	.dmi = quark_pci_dmi_data,
+ };
+ 
+ /**
+@@ -240,7 +235,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ 
+ 	pci_set_master(pdev);
+ 
+-	ret = info->setup(pdev, plat, info);
++	ret = info->setup(pdev, plat);
+ 	if (ret)
+ 		return ret;
+ 
+-- 
+2.16.4
+

+ 167 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0005-stmmac-pci-Use-dmi_system_id-table-for-retrieving-PH.patch

@@ -0,0 +1,167 @@
+From 1b2894107ad2d9de45402ecc4ffe14f075a08bbc Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 22 Jun 2017 08:18:01 +0200
+Subject: [PATCH 05/18] stmmac: pci: Use dmi_system_id table for retrieving PHY
+ addresses
+
+Commit 8d78b69091845386b6096f3adae98f28b9bf96ed upstream.
+
+Avoids reimplementation of DMI matching in stmmac_pci_find_phy_addr.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 97 ++++++++++++++++--------
+ 1 file changed, 64 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 9fe6368738ec..279a1355d75f 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -34,36 +34,39 @@
+  * negative value of the address means that MAC controller is not connected
+  * with PHY.
+  */
+-struct stmmac_pci_dmi_data {
+-	const char *name;
+-	const char *asset_tag;
++struct stmmac_pci_func_data {
+ 	unsigned int func;
+ 	int phy_addr;
+ };
+ 
++struct stmmac_pci_dmi_data {
++	const struct stmmac_pci_func_data *func;
++	size_t nfuncs;
++};
++
+ struct stmmac_pci_info {
+ 	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
+ };
+ 
+ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev,
+-				    struct stmmac_pci_dmi_data *dmi_data)
++				    const struct dmi_system_id *dmi_list)
+ {
+-	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
+-	const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG);
+-	unsigned int func = PCI_FUNC(pdev->devfn);
+-	struct stmmac_pci_dmi_data *dmi;
+-
+-	if (!name)
++	const struct stmmac_pci_func_data *func_data;
++	const struct stmmac_pci_dmi_data *dmi_data;
++	const struct dmi_system_id *dmi_id;
++	int func = PCI_FUNC(pdev->devfn);
++	size_t n;
++
++	dmi_id = dmi_first_match(dmi_list);
++	if (!dmi_id)
+ 		return -ENODEV;
+ 
+-	for (dmi = dmi_data; dmi->name && *dmi->name; dmi++) {
+-		if (!strcmp(dmi->name, name) && dmi->func == func) {
+-			/* If asset tag is provided, match on it as well. */
+-			if (dmi->asset_tag && strcmp(dmi->asset_tag, asset_tag))
+-				continue;
+-			return dmi->phy_addr;
+-		}
+-	}
++	dmi_data = dmi_id->driver_data;
++	func_data = dmi_data->func;
++
++	for (n = 0; n < dmi_data->nfuncs; n++, func_data++)
++		if (func_data->func == func)
++			return func_data->phy_addr;
+ 
+ 	return -ENODEV;
+ }
+@@ -97,34 +100,62 @@ static const struct stmmac_pci_info stmmac_pci_info = {
+ 	.setup = stmmac_default_data,
+ };
+ 
+-static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
++static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
+ 	{
+-		.name = "Galileo",
+ 		.func = 6,
+ 		.phy_addr = 1,
+ 	},
++};
++
++static const struct stmmac_pci_dmi_data galileo_stmmac_dmi_data = {
++	.func = galileo_stmmac_func_data,
++	.nfuncs = ARRAY_SIZE(galileo_stmmac_func_data),
++};
++
++static const struct stmmac_pci_func_data iot2040_stmmac_func_data[] = {
+ 	{
+-		.name = "GalileoGen2",
+ 		.func = 6,
+ 		.phy_addr = 1,
+ 	},
+ 	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-0YA2",
+-		.func = 6,
++		.func = 7,
+ 		.phy_addr = 1,
+ 	},
++};
++
++static const struct stmmac_pci_dmi_data iot2040_stmmac_dmi_data = {
++	.func = iot2040_stmmac_func_data,
++	.nfuncs = ARRAY_SIZE(iot2040_stmmac_func_data),
++};
++
++static const struct dmi_system_id quark_pci_dmi[] = {
+ 	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-1YA2",
+-		.func = 6,
+-		.phy_addr = 1,
++		.matches = {
++			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
++		},
++		.driver_data = (void *)&galileo_stmmac_dmi_data,
+ 	},
+ 	{
+-		.name = "SIMATIC IOT2000",
+-		.asset_tag = "6ES7647-0AA00-1YA2",
+-		.func = 7,
+-		.phy_addr = 1,
++		.matches = {
++			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
++		},
++		.driver_data = (void *)&galileo_stmmac_dmi_data,
++	},
++	{
++		.matches = {
++			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
++			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
++					"6ES7647-0AA00-0YA2"),
++		},
++		.driver_data = (void *)&galileo_stmmac_dmi_data,
++	},
++	{
++		.matches = {
++			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
++			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
++					"6ES7647-0AA00-1YA2"),
++		},
++		.driver_data = (void *)&iot2040_stmmac_dmi_data,
+ 	},
+ 	{}
+ };
+@@ -138,7 +169,7 @@ static int quark_default_data(struct pci_dev *pdev,
+ 	 * Refuse to load the driver and register net device if MAC controller
+ 	 * does not connect to any PHY interface.
+ 	 */
+-	ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi_data);
++	ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi);
+ 	if (ret < 0) {
+ 		/* Return error to the caller on DMI enabled boards. */
+ 		if (dmi_get_system_info(DMI_BOARD_NAME))
+-- 
+2.16.4
+

+ 47 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0006-stmmac-pci-Adjust-IOT2000-matching.patch

@@ -0,0 +1,47 @@
+From e3ba8c4f83c6c206a20e4645a37612b1e10580c6 Mon Sep 17 00:00:00 2001
+From: Su Bao Cheng <baocheng.su@siemens.com>
+Date: Fri, 12 Oct 2018 15:08:11 +0200
+Subject: [PATCH 06/18] stmmac: pci: Adjust IOT2000 matching
+
+Since there are more IOT2040 variants with identical hardware but
+different asset tags, the asset tag matching should be adjusted to
+support them.
+
+For the board name "SIMATIC IOT2000", currently there are 2 types of
+hardware, IOT2020 and IOT2040. The IOT2020 is identified by its unique
+asset tag. Match on it first. If we then match on the board name only,
+we will catch all IOT2040 variants. In the future there will be no other
+devices with the "SIMATIC IOT2000" DMI board name but different
+hardware.
+
+Signed-off-by: Su Bao Cheng <baocheng.su@siemens.com>
+Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 279a1355d75f..ac733d4d3ed4 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -149,11 +149,15 @@ static const struct dmi_system_id quark_pci_dmi[] = {
+ 		},
+ 		.driver_data = (void *)&galileo_stmmac_dmi_data,
+ 	},
++	/*
++	 * There are 2 types of SIMATIC IOT2000: IOT2020 and IOT2040.
++	 * The asset tag "6ES7647-0AA00-0YA2" is only for IOT2020 which
++	 * has only one pci network device while other asset tags are
++	 * for IOT2040 which has two.
++	 */
+ 	{
+ 		.matches = {
+ 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+-			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+-					"6ES7647-0AA00-1YA2"),
+ 		},
+ 		.driver_data = (void *)&iot2040_stmmac_dmi_data,
+ 	},
+-- 
+2.16.4
+

+ 44 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0007-serial-8250_exar-Adjust-IOT2000-matching.patch

@@ -0,0 +1,44 @@
+From df74e188ffc38176d4caba969e104d2ab2e4e609 Mon Sep 17 00:00:00 2001
+From: Su Bao Cheng <baocheng.su@siemens.com>
+Date: Fri, 12 Oct 2018 15:12:37 +0200
+Subject: [PATCH 07/18] serial: 8250_exar: Adjust IOT2000 matching
+
+Since there are more IOT2040 variants with identical hardware but
+different asset tags, the asset tag matching should be adjusted to
+support them.
+
+As only the IOT2040 variants have the Exar chip on board, matching on
+their board name is enough. In the future there will be no other devices
+with the "SIMATIC IOT2000" DMI board name but different hardware.
+
+Signed-off-by: Su Bao Cheng <baocheng.su@siemens.com>
+Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/tty/serial/8250/8250_exar.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
+index be82707d6cb8..3eb3a7674a0f 100644
+--- a/drivers/tty/serial/8250/8250_exar.c
++++ b/drivers/tty/serial/8250/8250_exar.c
+@@ -338,12 +338,15 @@ static const struct exar8250_platform iot2040_platform = {
+ 	.register_gpio = iot2040_register_gpio,
+ };
+ 
++/*
++ * For SIMATIC IOT2000, only IOT2040 and its variants have the Exar device,
++ * IOT2020 doesn't have. Therefore it is sufficient to match on the common
++ * board name after the device was found.
++ */
+ static const struct dmi_system_id exar_platforms[] = {
+ 	{
+ 		.matches = {
+ 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+-			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+-					"6ES7647-0AA00-1YA2"),
+ 		},
+ 		.driver_data = (void *)&iot2040_platform,
+ 	},
+-- 
+2.16.4
+

+ 45 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0008-mfd-intel_quark_i2c_gpio-Adjust-IOT2000-matching.patch

@@ -0,0 +1,45 @@
+From 6e378b789ebcfcdc4ae957b25f1ac6eb2ef64edc Mon Sep 17 00:00:00 2001
+From: Su Bao Cheng <baocheng.su@siemens.com>
+Date: Fri, 12 Oct 2018 15:05:07 +0200
+Subject: [PATCH 08/18] mfd: intel_quark_i2c_gpio: Adjust IOT2000 matching
+
+Since there are more IOT2040 variants with identical hardware but
+different asset tags, the asset tag matching should be adjusted to
+support them.
+
+For the board name "SIMATIC IOT2000", currently there are 2 types of
+hardware, IOT2020 and IOT2040. Both are identical regarding the
+intel_quark_i2c_gpio. In the future there will be no other devices with
+the "SIMATIC IOT2000" DMI board name but different hardware. So remove
+the asset tag matching from this driver.
+
+Signed-off-by: Su Bao Cheng <baocheng.su@siemens.com>
+Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/mfd/intel_quark_i2c_gpio.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
+index 1c09604978d3..ad70a058bea8 100644
+--- a/drivers/mfd/intel_quark_i2c_gpio.c
++++ b/drivers/mfd/intel_quark_i2c_gpio.c
+@@ -76,16 +76,6 @@ static const struct dmi_system_id dmi_platform_info[] = {
+ 	{
+ 		.matches = {
+ 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+-			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+-					"6ES7647-0AA00-0YA2"),
+-		},
+-		.driver_data = (void *)400000,
+-	},
+-	{
+-		.matches = {
+-			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+-			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+-					"6ES7647-0AA00-1YA2"),
+ 		},
+ 		.driver_data = (void *)400000,
+ 	},
+-- 
+2.16.4
+

+ 86 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0009-gpio-sch-use-gpiochip-data-pointer.patch

@@ -0,0 +1,86 @@
+From cf3d1330c71d47c4cdb9268f68d2ee5931890d93 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Mon, 7 Dec 2015 14:21:49 +0100
+Subject: [PATCH 09/18] gpio: sch: use gpiochip data pointer
+
+This makes the driver use the data pointer added to the gpio_chip
+to store a pointer to the state container instead of relying on
+container_of().
+
+Cc: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/gpio/gpio-sch.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index b72906f5b999..23907fc080a3 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -41,8 +41,6 @@ struct sch_gpio {
+ 	unsigned short resume_base;
+ };
+ 
+-#define to_sch_gpio(gc)	container_of(gc, struct sch_gpio, chip)
+-
+ static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+ 				unsigned reg)
+ {
+@@ -65,7 +63,7 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
+ 
+ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
+ {
+-	struct sch_gpio *sch = to_sch_gpio(gc);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 	unsigned short offset, bit;
+ 	u8 reg_val;
+ 
+@@ -80,7 +78,7 @@ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
+ static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
+ 			     int val)
+ {
+-	struct sch_gpio *sch = to_sch_gpio(gc);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 	unsigned short offset, bit;
+ 	u8 reg_val;
+ 
+@@ -97,7 +95,7 @@ static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
+ 
+ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+ {
+-	struct sch_gpio *sch = to_sch_gpio(gc);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+ 	sch_gpio_reg_set(gc, gpio_num, GIO, 1);
+@@ -112,7 +110,7 @@ static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
+ 
+ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+ {
+-	struct sch_gpio *sch = to_sch_gpio(gc);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+ 	sch_gpio_reg_set(gc, gpio_num, GLV, val);
+@@ -122,7 +120,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ 				  int val)
+ {
+-	struct sch_gpio *sch = to_sch_gpio(gc);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+ 	sch_gpio_reg_set(gc, gpio_num, GIO, 0);
+@@ -217,7 +215,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ 
+ 	platform_set_drvdata(pdev, sch);
+ 
+-	return gpiochip_add(&sch->chip);
++	return gpiochip_add_data(&sch->chip, sch);
+ }
+ 
+ static int sch_gpio_remove(struct platform_device *pdev)
+-- 
+2.16.4
+

+ 46 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0010-gpio-sch-Use-devm_gpiochip_add_data-for-gpio-registr.patch

@@ -0,0 +1,46 @@
+From 6a930e4d040061edcaf0c3e3e43a10acdc20f09c Mon Sep 17 00:00:00 2001
+From: Laxman Dewangan <ldewangan@nvidia.com>
+Date: Mon, 22 Feb 2016 17:43:28 +0530
+Subject: [PATCH 10/18] gpio: sch: Use devm_gpiochip_add_data() for gpio
+ registration
+
+Use devm_gpiochip_add_data() for GPIO registration and remove the
+need of driver callback .remove.
+
+Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
+---
+ drivers/gpio/gpio-sch.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index 23907fc080a3..bbf9b2a34da8 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -215,15 +215,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ 
+ 	platform_set_drvdata(pdev, sch);
+ 
+-	return gpiochip_add_data(&sch->chip, sch);
+-}
+-
+-static int sch_gpio_remove(struct platform_device *pdev)
+-{
+-	struct sch_gpio *sch = platform_get_drvdata(pdev);
+-
+-	gpiochip_remove(&sch->chip);
+-	return 0;
++	return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
+ }
+ 
+ static struct platform_driver sch_gpio_driver = {
+@@ -231,7 +223,6 @@ static struct platform_driver sch_gpio_driver = {
+ 		.name = "sch_gpio",
+ 	},
+ 	.probe		= sch_gpio_probe,
+-	.remove		= sch_gpio_remove,
+ };
+ 
+ module_platform_driver(sch_gpio_driver);
+-- 
+2.16.4
+

+ 114 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0011-gpio-sch-Fix-Oops-on-module-load-on-Asus-Eee-PC-1201.patch

@@ -0,0 +1,114 @@
+From 9fd1991d762b6092f462f3cc551b2d7df3009b52 Mon Sep 17 00:00:00 2001
+From: Colin Pitrat <colin.pitrat@gmail.com>
+Date: Sat, 18 Jun 2016 19:05:04 +0100
+Subject: [PATCH 11/18] gpio: sch: Fix Oops on module load on Asus Eee PC 1201
+
+This fixes the issue descirbe in bug 117531
+(https://bugzilla.kernel.org/show_bug.cgi?id=117531).
+It's a regression introduced in linux 4.5 that causes a Oops at load of
+gpio_sch and prevents powering off the computer.
+
+The issue is that sch_gpio_reg_set is called in sch_gpio_probe before
+gpio_chip data is initialized with the pointer to the sch_gpio struct. As
+sch_gpio_reg_set calls gpiochip_get_data, it returns NULL which causes
+the Oops.
+
+The patch follows Mika's advice (https://lkml.org/lkml/2016/5/9/61) and
+consists in modifying sch_gpio_reg_get and sch_gpio_reg_set to take a
+sch_gpio struct directly instead of a gpio_chip, which avoids the call to
+gpiochip_get_data.
+
+Thanks Mika for your patience with me :-)
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Colin Pitrat <colin.pitrat@gmail.com>
+Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/gpio/gpio-sch.c | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index bbf9b2a34da8..5f72b177fc80 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -61,9 +61,8 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
+ 	return gpio % 8;
+ }
+ 
+-static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
++static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg)
+ {
+-	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 	unsigned short offset, bit;
+ 	u8 reg_val;
+ 
+@@ -75,10 +74,9 @@ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
+ 	return reg_val;
+ }
+ 
+-static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
++static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,
+ 			     int val)
+ {
+-	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 	unsigned short offset, bit;
+ 	u8 reg_val;
+ 
+@@ -98,14 +96,15 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+-	sch_gpio_reg_set(gc, gpio_num, GIO, 1);
++	sch_gpio_reg_set(sch, gpio_num, GIO, 1);
+ 	spin_unlock(&sch->lock);
+ 	return 0;
+ }
+ 
+ static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
+ {
+-	return sch_gpio_reg_get(gc, gpio_num, GLV);
++	struct sch_gpio *sch = gpiochip_get_data(gc);
++	return sch_gpio_reg_get(sch, gpio_num, GLV);
+ }
+ 
+ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+@@ -113,7 +112,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+-	sch_gpio_reg_set(gc, gpio_num, GLV, val);
++	sch_gpio_reg_set(sch, gpio_num, GLV, val);
+ 	spin_unlock(&sch->lock);
+ }
+ 
+@@ -123,7 +122,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
+ 
+ 	spin_lock(&sch->lock);
+-	sch_gpio_reg_set(gc, gpio_num, GIO, 0);
++	sch_gpio_reg_set(sch, gpio_num, GIO, 0);
+ 	spin_unlock(&sch->lock);
+ 
+ 	/*
+@@ -182,13 +181,13 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ 		 * GPIO7 is configured by the CMC as SLPIOVR
+ 		 * Enable GPIO[9:8] core powered gpios explicitly
+ 		 */
+-		sch_gpio_reg_set(&sch->chip, 8, GEN, 1);
+-		sch_gpio_reg_set(&sch->chip, 9, GEN, 1);
++		sch_gpio_reg_set(sch, 8, GEN, 1);
++		sch_gpio_reg_set(sch, 9, GEN, 1);
+ 		/*
+ 		 * SUS_GPIO[2:0] enabled by default
+ 		 * Enable SUS_GPIO3 resume powered gpio explicitly
+ 		 */
+-		sch_gpio_reg_set(&sch->chip, 13, GEN, 1);
++		sch_gpio_reg_set(sch, 13, GEN, 1);
+ 		break;
+ 
+ 	case PCI_DEVICE_ID_INTEL_ITC_LPC:
+-- 
+2.16.4
+

+ 45 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0012-gpio-sch-Implement-.get_direction.patch

@@ -0,0 +1,45 @@
+From 8fec046f568e2b946abd55a82d5417717a115b21 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 27 Jun 2018 10:39:31 +0200
+Subject: [PATCH 12/18] gpio: sch: Implement .get_direction()
+
+It's pretty simple to implement the .get_direction() for this
+chip, so let's just do it.
+
+Cc: Denis Turischev <denis.turischev@compulab.co.il>
+Cc: Daniel Krueger <daniel.krueger@systec-electronic.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/gpio/gpio-sch.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index 5f72b177fc80..6715828c3940 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -138,6 +138,13 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ 	return 0;
+ }
+ 
++static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num)
++{
++	struct sch_gpio *sch = gpiochip_get_data(gc);
++
++	return sch_gpio_reg_get(sch, gpio_num, GIO);
++}
++
+ static struct gpio_chip sch_gpio_chip = {
+ 	.label			= "sch_gpio",
+ 	.owner			= THIS_MODULE,
+@@ -145,6 +152,7 @@ static struct gpio_chip sch_gpio_chip = {
+ 	.get			= sch_gpio_get,
+ 	.direction_output	= sch_gpio_direction_out,
+ 	.set			= sch_gpio_set,
++	.get_direction		= sch_gpio_get_direction,
+ };
+ 
+ static int sch_gpio_probe(struct platform_device *pdev)
+-- 
+2.16.4
+

+ 230 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0013-gpio-sch-Add-interrupt-support.patch

@@ -0,0 +1,230 @@
+From 53c90b014f54743b5a2180f90b90b1f198535583 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Wed, 17 Apr 2019 22:26:22 +0200
+Subject: [PATCH 13/18] gpio: sch: Add interrupt support
+
+Validated on the Quark platform, this adds interrupt support on rising
+and/or falling edges.
+
+Backported from upstream, skipping clean roll-back or errors due to some
+missing devm_* services.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/gpio/gpio-sch.c | 140 +++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 133 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index 6715828c3940..1d1dadebc8c1 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -32,6 +32,10 @@
+ #define GEN	0x00
+ #define GIO	0x04
+ #define GLV	0x08
++#define GTPE	0x0c
++#define GTNE	0x10
++#define GGPE	0x14
++#define GTS	0x1c
+ 
+ struct sch_gpio {
+ 	struct gpio_chip chip;
+@@ -39,6 +43,7 @@ struct sch_gpio {
+ 	unsigned short iobase;
+ 	unsigned short core_base;
+ 	unsigned short resume_base;
++	int irq_base;
+ };
+ 
+ static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+@@ -94,10 +99,11 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,
+ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+ {
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
++	unsigned long flags;
+ 
+-	spin_lock(&sch->lock);
++	spin_lock_irqsave(&sch->lock, flags);
+ 	sch_gpio_reg_set(sch, gpio_num, GIO, 1);
+-	spin_unlock(&sch->lock);
++	spin_unlock_irqrestore(&sch->lock, flags);
+ 	return 0;
+ }
+ 
+@@ -110,20 +116,22 @@ static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
+ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+ {
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
++	unsigned long flags;
+ 
+-	spin_lock(&sch->lock);
++	spin_lock_irqsave(&sch->lock, flags);
+ 	sch_gpio_reg_set(sch, gpio_num, GLV, val);
+-	spin_unlock(&sch->lock);
++	spin_unlock_irqrestore(&sch->lock, flags);
+ }
+ 
+ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ 				  int val)
+ {
+ 	struct sch_gpio *sch = gpiochip_get_data(gc);
++	unsigned long flags;
+ 
+-	spin_lock(&sch->lock);
++	spin_lock_irqsave(&sch->lock, flags);
+ 	sch_gpio_reg_set(sch, gpio_num, GIO, 0);
+-	spin_unlock(&sch->lock);
++	spin_unlock_irqrestore(&sch->lock, flags);
+ 
+ 	/*
+ 	 * according to the datasheet, writing to the level register has no
+@@ -145,6 +153,12 @@ static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num)
+ 	return sch_gpio_reg_get(sch, gpio_num, GIO);
+ }
+ 
++static int sch_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset)
++{
++	struct sch_gpio *sch = gpiochip_get_data(gpio);
++	return sch->irq_base + offset;
++}
++
+ static struct gpio_chip sch_gpio_chip = {
+ 	.label			= "sch_gpio",
+ 	.owner			= THIS_MODULE,
+@@ -153,12 +167,96 @@ static struct gpio_chip sch_gpio_chip = {
+ 	.direction_output	= sch_gpio_direction_out,
+ 	.set			= sch_gpio_set,
+ 	.get_direction		= sch_gpio_get_direction,
++	.to_irq			= sch_gpio_to_irq,
+ };
+ 
++static u32 sch_sci_handler(void *context)
++{
++	struct sch_gpio *sch = context;
++	unsigned long core_status, resume_status;
++	unsigned int resume_gpios, offset;
++
++	core_status = inl(sch->iobase + GTS);
++	resume_status = inl(sch->iobase + GTS + 0x20);
++
++	if (core_status == 0 && resume_status == 0)
++		return ACPI_INTERRUPT_NOT_HANDLED;
++
++	for_each_set_bit(offset, &core_status, sch->resume_base)
++		generic_handle_irq(sch->irq_base + offset);
++
++	resume_gpios = sch->chip.ngpio - sch->resume_base;
++	for_each_set_bit(offset, &resume_status, resume_gpios)
++		generic_handle_irq(sch->irq_base + sch->resume_base + offset);
++
++	outl(core_status, sch->iobase + GTS);
++	outl(resume_status, sch->iobase + GTS + 0x20);
++
++	return ACPI_INTERRUPT_HANDLED;
++}
++
++static int sch_irq_type(struct irq_data *d, unsigned int type)
++{
++	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
++	struct sch_gpio *sch = gc->private;
++	unsigned int gpio_num = d->irq - sch->irq_base;
++	unsigned long flags;
++	int rising = 0;
++	int falling = 0;
++
++	switch (type & IRQ_TYPE_SENSE_MASK) {
++	case IRQ_TYPE_EDGE_RISING:
++		rising = 1;
++		break;
++	case IRQ_TYPE_EDGE_FALLING:
++		falling = 1;
++		break;
++	case IRQ_TYPE_EDGE_BOTH:
++		rising = 1;
++		falling = 1;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&sch->lock, flags);
++	sch_gpio_reg_set(sch, gpio_num, GTPE, rising);
++	sch_gpio_reg_set(sch, gpio_num, GTNE, falling);
++	spin_unlock_irqrestore(&sch->lock, flags);
++
++	return 0;
++}
++
++static void sch_irq_set_enable(struct irq_data *d, int val)
++{
++	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
++	struct sch_gpio *sch = gc->private;
++	unsigned int gpio_num = d->irq - sch->irq_base;
++	unsigned long flags;
++
++	spin_lock_irqsave(&sch->lock, flags);
++	sch_gpio_reg_set(sch, gpio_num, GGPE, val);
++	spin_unlock_irqrestore(&sch->lock, flags);
++}
++
++static void sch_irq_mask(struct irq_data *d)
++{
++	sch_irq_set_enable(d, 0);
++}
++
++static void sch_irq_unmask(struct irq_data *d)
++{
++	sch_irq_set_enable(d, 1);
++}
++
+ static int sch_gpio_probe(struct platform_device *pdev)
+ {
++	struct irq_chip_generic *gc;
++	struct irq_chip_type *ct;
+ 	struct sch_gpio *sch;
+ 	struct resource *res;
++	acpi_status status;
++	int irq_base, ret;
+ 
+ 	sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+ 	if (!sch)
+@@ -222,7 +320,35 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ 
+ 	platform_set_drvdata(pdev, sch);
+ 
+-	return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
++	ret = devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
++	if (ret)
++		return ret;
++
++	irq_base = irq_alloc_descs(-1, 0, sch->chip.ngpio, NUMA_NO_NODE);
++	if (irq_base < 0)
++		return irq_base;
++	sch->irq_base = irq_base;
++
++	gc = irq_alloc_generic_chip("sch_gpio", 1, irq_base,
++				    NULL, handle_simple_irq);
++	if (!gc)
++		return -ENOMEM;
++
++	gc->private = sch;
++	ct = gc->chip_types;
++
++	ct->chip.irq_mask = sch_irq_mask;
++	ct->chip.irq_unmask = sch_irq_unmask;
++	ct->chip.irq_set_type = sch_irq_type;
++
++	irq_setup_generic_chip(gc, IRQ_MSK(sch->chip.ngpio),
++			       0, IRQ_NOREQUEST | IRQ_NOPROBE, 0);
++
++	status = acpi_install_sci_handler(sch_sci_handler, sch);
++	if (ACPI_FAILURE(status))
++		return -EINVAL;
++
++	return 0;
+ }
+ 
+ static struct platform_driver sch_gpio_driver = {
+-- 
+2.16.4
+

+ 44 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0014-iot2000-hack-Work-around-DSDT-mistake.patch

@@ -0,0 +1,44 @@
+From f43a54ec8a8b5f070d4b1b59f3d47dc03f74ad32 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 25 May 2017 11:09:42 +0200
+Subject: [PATCH 14/18] iot2000-hack: Work around DSDT mistake
+
+Until we have a new firmware revision, fix up the incorrect GPIO
+interrupt pin in software.
+
+Nothing for upstream.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/gpio/gpiolib-acpi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
+index 16a7b6816744..304855b3ecb8 100644
+--- a/drivers/gpio/gpiolib-acpi.c
++++ b/drivers/gpio/gpiolib-acpi.c
+@@ -10,6 +10,7 @@
+  * published by the Free Software Foundation.
+  */
+ 
++#include <linux/dmi.h>
+ #include <linux/errno.h>
+ #include <linux/gpio.h>
+ #include <linux/gpio/consumer.h>
+@@ -408,6 +409,13 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
+ 		if (pin_index >= agpio->pin_table_length)
+ 			return 1;
+ 
++		if (!strcmp(dmi_get_system_info(DMI_BOARD_NAME),
++			    "SIMATIC IOT2000") &&
++		    !strcmp(agpio->resource_source.string_ptr,
++			    "\\_SB.PCI0.GIP0.GPO") &&
++		    agpio->pin_table[pin_index] == 9)
++			agpio->pin_table[pin_index] = 1;
++
+ 		lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
+ 					      agpio->pin_table[pin_index]);
+ 		lookup->info.gpioint =
+-- 
+2.16.4
+

+ 42 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0015-iot2000-hack-Adjust-pca9685-gpio-base-for-legacy-com.patch

@@ -0,0 +1,42 @@
+From 88f2d0ccdee1f1890af0d049c60fe24f6c6eb048 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 25 May 2017 13:05:12 +0200
+Subject: [PATCH 15/18] iot2000-hack: Adjust pca9685-gpio base for legacy
+ compatibility
+
+mraa and the Arduino runtime expect this.
+
+Not for upstream.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/pwm/pwm-pca9685.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
+index d2b92e940e38..611b9263a896 100644
+--- a/drivers/pwm/pwm-pca9685.c
++++ b/drivers/pwm/pwm-pca9685.c
+@@ -19,6 +19,7 @@
+  * this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
++#include <linux/dmi.h>
+ #include <linux/acpi.h>
+ #include <linux/gpio/driver.h>
+ #include <linux/i2c.h>
+@@ -222,7 +223,10 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
+ 	pca->gpio.direction_output = pca9685_pwm_gpio_direction_output;
+ 	pca->gpio.get = pca9685_pwm_gpio_get;
+ 	pca->gpio.set = pca9685_pwm_gpio_set;
+-	pca->gpio.base = -1;
++	if (!strcmp(dmi_get_system_info(DMI_BOARD_NAME), "SIMATIC IOT2000"))
++		pca->gpio.base = 64;
++	else
++		pca->gpio.base = -1;
+ 	pca->gpio.ngpio = PCA9685_MAXCHAN;
+ 	pca->gpio.can_sleep = true;
+ 
+-- 
+2.16.4
+

+ 99 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0016-iot2000-hack-gpio-pca953x-provide-GPIO-base-based-on.patch

@@ -0,0 +1,99 @@
+From 5c102aea3f4ffea811eec719edd638fc7888e9c3 Mon Sep 17 00:00:00 2001
+From: Yong Li <sdliyong@gmail.com>
+Date: Thu, 31 Mar 2016 15:33:08 +0800
+Subject: [PATCH 16/18] iot2000-hack: gpio: pca953x: provide GPIO base based on
+ _UID
+
+Custom kernel for Intel Galileo Gen2 provides and moreover libmraa relies on
+the continuous GPIO space. To do such we have to configure GPIO base per each
+GPIO expander. The only value we can use is the ACPI _UID.
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+Upstream-status: Inappropriate, custom code for legacy userspace
+Signed-off-by: Saul Wold <sgw@linux.intel.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+Signed-off-by: Yong Li <sdliyong@gmail.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/gpio/gpio-pca953x.c | 44 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 37 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
+index b45ba6be69ef..8b467c0db1cb 100644
+--- a/drivers/gpio/gpio-pca953x.c
++++ b/drivers/gpio/gpio-pca953x.c
+@@ -82,12 +82,6 @@ static const struct i2c_device_id pca953x_id[] = {
+ };
+ MODULE_DEVICE_TABLE(i2c, pca953x_id);
+ 
+-static const struct acpi_device_id pca953x_acpi_ids[] = {
+-	{ "INT3491", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
+-	{ }
+-};
+-MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
+-
+ #define MAX_BANK 5
+ #define BANK_SZ 8
+ 
+@@ -119,6 +113,35 @@ static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
+ 	return container_of(gc, struct pca953x_chip, gpio_chip);
+ }
+ 
++struct pca953x_info {
++	kernel_ulong_t driver_data;
++	void (*setup)(struct pca953x_chip *chip);
++};
++
++static void pca953x_setup_int3491(struct pca953x_chip *chip)
++{
++	struct acpi_device *adev = ACPI_COMPANION(&chip->client->dev);
++	unsigned int uid;
++
++	if (kstrtouint(acpi_device_uid(adev), 0, &uid) || !uid--)
++		return;
++
++	chip->gpio_start = 8 /* sch_gpio */ +
++			   8 /* gpio-dwapb */ +
++			  16 /* pca9535 */ * uid;
++}
++
++static const struct pca953x_info pca953x_info_int3491 = {
++	.driver_data = 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL,
++	.setup = pca953x_setup_int3491,
++};
++
++static const struct acpi_device_id pca953x_acpi_ids[] = {
++	{ "INT3491",  (kernel_ulong_t)&pca953x_info_int3491 },
++	{ }
++};
++MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
++
+ static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+ 				int off)
+ {
+@@ -731,12 +754,19 @@ static int pca953x_probe(struct i2c_client *client,
+ 		chip->driver_data = id->driver_data;
+ 	} else {
+ 		const struct acpi_device_id *id;
++		const struct pca953x_info *info;
+ 
+ 		id = acpi_match_device(pca953x_acpi_ids, &client->dev);
+ 		if (!id)
+ 			return -ENODEV;
+ 
+-		chip->driver_data = id->driver_data;
++		info = (struct pca953x_info *)id->driver_data;
++		if (!info)
++			return -ENODEV;
++
++		chip->driver_data = info->driver_data;
++		if (info->setup)
++			info->setup(chip);
+ 	}
+ 
+ 	chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
+-- 
+2.16.4
+

+ 334 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0017-iot2000-hack-gpio-pca953x-add-drive-property.patch

@@ -0,0 +1,334 @@
+From a66a980a3520859c1a01fc65f76c4f2abd2a2eed Mon Sep 17 00:00:00 2001
+From: Yong Li <sdliyong@gmail.com>
+Date: Thu, 31 Mar 2016 15:33:09 +0800
+Subject: [PATCH 17/18] iot2000-hack: gpio-pca953x: add "drive" property
+
+Galileo gen 2 has support for setting GPIO modes. Expose these
+properties through the GPIO sysfs interface. This approach is bit hacky,
+since it changes the interface semantics.
+
+The original patch was by Josef Ahmad <josef.ahmad@linux.intel.com> and
+made on top of kernel 3.8.
+
+Not for upstream.
+
+Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com>
+Signed-off-by: Jussi Laako <jussi.laako@linux.intel.com>
+Signed-off-by: Saul Wold <sgw@linux.intel.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+Signed-off-by: Yong Li <sdliyong@gmail.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/gpio/gpio-pca953x.c   | 42 +++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  | 78 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib.c        | 17 ++++++++++
+ drivers/gpio/gpiolib.h        |  4 +++
+ include/asm-generic/gpio.h    |  5 +++
+ include/linux/gpio.h          | 10 ++++++
+ include/linux/gpio/consumer.h | 11 ++++++
+ include/linux/gpio/driver.h   |  2 ++
+ 8 files changed, 169 insertions(+)
+
+diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
+index 8b467c0db1cb..ca1f6f4d6f59 100644
+--- a/drivers/gpio/gpio-pca953x.c
++++ b/drivers/gpio/gpio-pca953x.c
+@@ -40,6 +40,8 @@
+ #define PCA957X_INTS		7
+ 
+ #define PCAL953X_IN_LATCH	34
++#define PCAL953X_PUPD_EN	35
++#define PCAL953X_PUPD_SEL	36
+ #define PCAL953X_INT_MASK	37
+ #define PCAL953X_INT_STAT	38
+ 
+@@ -380,6 +382,43 @@ exit:
+ 	mutex_unlock(&chip->i2c_lock);
+ }
+ 
++static int pca953x_gpio_set_drive(struct gpio_chip *gc,
++				 unsigned off, unsigned mode)
++{
++	struct pca953x_chip *chip;
++	int ret = 0;
++	int val;
++
++	chip = container_of(gc, struct pca953x_chip, gpio_chip);
++
++	if (!(chip->driver_data & PCA_PCAL))
++		return -EINVAL;
++
++	mutex_lock(&chip->i2c_lock);
++
++	switch (mode) {
++	case GPIOF_DRIVE_PULLUP:
++		ret = pca953x_write_single(chip, PCAL953X_PUPD_EN, 1, off) ||
++			pca953x_write_single(chip, PCAL953X_PUPD_SEL, 1, off);
++		break;
++	case GPIOF_DRIVE_PULLDOWN:
++		ret = pca953x_write_single(chip, PCAL953X_PUPD_EN, 1, off) ||
++			pca953x_write_single(chip, PCAL953X_PUPD_SEL, 0, off);
++		break;
++	case GPIOF_DRIVE_STRONG:
++	case GPIOF_DRIVE_HIZ:
++		ret = pca953x_read_single(chip, PCAL953X_PUPD_EN, &val, off) ||
++			pca953x_write_single(chip, PCAL953X_PUPD_EN, 0, off) ||
++			pca953x_write_single(chip, PCAL953X_PUPD_SEL, val, off);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	mutex_unlock(&chip->i2c_lock);
++	return ret;
++}
++
+ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+ {
+ 	struct gpio_chip *gc;
+@@ -398,6 +437,9 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+ 	gc->dev = &chip->client->dev;
+ 	gc->owner = THIS_MODULE;
+ 	gc->names = chip->names;
++
++	if (chip->driver_data & PCA_PCAL)
++		gc->set_drive = pca953x_gpio_set_drive;
+ }
+ 
+ #ifdef CONFIG_GPIO_PCA953X_IRQ
+diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
+index b57ed8e55ab5..72a8647146fa 100644
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -7,6 +7,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/kdev_t.h>
+ #include <linux/slab.h>
++#include <linux/gpio.h>
+ 
+ #include "gpiolib.h"
+ 
+@@ -350,6 +351,82 @@ static ssize_t active_low_store(struct device *dev,
+ }
+ static DEVICE_ATTR_RW(active_low);
+ 
++
++static ssize_t gpio_drive_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	const struct gpio_desc	*desc = dev_get_drvdata(dev);
++	ssize_t			status;
++
++	mutex_lock(&sysfs_lock);
++
++	if (!test_bit(FLAG_EXPORT, &desc->flags)) {
++		status = -EIO;
++	} else {
++		if (test_bit(FLAG_PULLUP, &desc->flags))
++			status = sprintf(buf, "pullup\n");
++		else if (test_bit(FLAG_PULLDOWN, &desc->flags))
++			status = sprintf(buf, "pulldown\n");
++		else if (test_bit(FLAG_STRONG, &desc->flags))
++			status = sprintf(buf, "strong\n");
++		else if (test_bit(FLAG_HIZ, &desc->flags))
++			status = sprintf(buf, "hiz\n");
++		else
++			status = -EINVAL;
++	}
++
++	mutex_unlock(&sysfs_lock);
++	return status;
++}
++
++static ssize_t gpio_drive_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t size)
++{
++	struct gpio_desc	*desc = dev_get_drvdata(dev);
++	ssize_t			status;
++
++	mutex_lock(&sysfs_lock);
++
++	if (!test_bit(FLAG_EXPORT, &desc->flags))
++		status = -EIO;
++	else {
++		clear_bit(FLAG_PULLUP, &desc->flags);
++		clear_bit(FLAG_PULLDOWN, &desc->flags);
++		clear_bit(FLAG_STRONG, &desc->flags);
++		clear_bit(FLAG_HIZ, &desc->flags);
++		if (sysfs_streq(buf, "pullup")) {
++			status = gpiod_set_drive(desc, GPIOF_DRIVE_PULLUP);
++			if (!status) {
++				set_bit(FLAG_PULLUP, &desc->flags);
++			}
++		} else if (sysfs_streq(buf, "pulldown")) {
++			status = gpiod_set_drive(desc, GPIOF_DRIVE_PULLDOWN);
++			if (!status) {
++				set_bit(FLAG_PULLDOWN, &desc->flags);
++			}
++		} else if (sysfs_streq(buf, "strong")) {
++			status = gpiod_set_drive(desc, GPIOF_DRIVE_STRONG);
++			if (!status) {
++				set_bit(FLAG_STRONG, &desc->flags);
++			}
++		} else if (sysfs_streq(buf, "hiz")) {
++			status = gpiod_set_drive(desc, GPIOF_DRIVE_HIZ);
++			if (!status) {
++				set_bit(FLAG_HIZ, &desc->flags);
++			}
++		} else {
++			status = -EINVAL;
++		}
++	}
++
++	mutex_unlock(&sysfs_lock);
++	return status ? : size;
++}
++
++static DEVICE_ATTR(drive, 0644,
++		gpio_drive_show, gpio_drive_store);
++
++
+ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
+ 			       int n)
+ {
+@@ -377,6 +454,7 @@ static struct attribute *gpio_attrs[] = {
+ 	&dev_attr_edge.attr,
+ 	&dev_attr_value.attr,
+ 	&dev_attr_active_low.attr,
++	&dev_attr_drive.attr,
+ 	NULL,
+ };
+ 
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 827510dbba30..d19928b9a311 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1315,6 +1315,23 @@ int gpiod_is_active_low(const struct gpio_desc *desc)
+ }
+ EXPORT_SYMBOL_GPL(gpiod_is_active_low);
+ 
++int gpiod_set_drive(struct gpio_desc *desc, unsigned mode)
++{
++	struct gpio_chip	*chip;
++
++	chip = desc->chip;
++	if (!chip || !chip->set || !chip->set_drive)
++		goto fail;
++
++	might_sleep_if(chip->can_sleep);
++
++	return chip->set_drive(chip, gpio_chip_hwgpio(desc), mode);
++
++fail:
++	return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(gpiod_set_drive);
++
+ /* I/O calls are only valid after configuration completed; the relevant
+  * "is this a valid GPIO" error checks should already have been done.
+  *
+diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
+index 07541c5670e6..cfa7406b10fd 100644
+--- a/drivers/gpio/gpiolib.h
++++ b/drivers/gpio/gpiolib.h
+@@ -96,6 +96,10 @@ struct gpio_desc {
+ #define FLAG_OPEN_SOURCE 8	/* Gpio is open source type */
+ #define FLAG_USED_AS_IRQ 9	/* GPIO is connected to an IRQ */
+ #define FLAG_IS_HOGGED	11	/* GPIO is hogged */
++#define FLAG_PULLUP	12	/* Gpio drive is resistive pullup */
++#define FLAG_PULLDOWN	13	/* Gpio drive is resistive pulldown */
++#define FLAG_STRONG	14	/* Gpio drive is strong (fast output) */
++#define FLAG_HIZ	15	/* Gpio drive is Hi-Z (input) */
+ 
+ 	/* Connection label */
+ 	const char		*label;
+diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
+index 40ec1433f05d..519e8d458878 100644
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -76,6 +76,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+ 	return gpiod_set_debounce(gpio_to_desc(gpio), debounce);
+ }
+ 
++static inline int gpio_set_drive(unsigned gpio, unsigned mode)
++{
++	return gpiod_set_drive(gpio_to_desc(gpio), mode);
++}
++
+ static inline int gpio_get_value_cansleep(unsigned gpio)
+ {
+ 	return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
+diff --git a/include/linux/gpio.h b/include/linux/gpio.h
+index d12b5d566e4b..344e62d27700 100644
+--- a/include/linux/gpio.h
++++ b/include/linux/gpio.h
+@@ -30,6 +30,11 @@
+ #define GPIOF_EXPORT_DIR_FIXED	(GPIOF_EXPORT)
+ #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
+ 
++#define GPIOF_DRIVE_PULLUP	(1 << 7)
++#define GPIOF_DRIVE_PULLDOWN	(1 << 8)
++#define GPIOF_DRIVE_STRONG	(1 << 9)
++#define GPIOF_DRIVE_HIZ		(1 << 10)
++
+ /**
+  * struct gpio - a structure describing a GPIO with configuration
+  * @gpio:	the GPIO number
+@@ -148,6 +153,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+ 	return -ENOSYS;
+ }
+ 
++static inline int gpio_set_drive(unsigned gpio, unsigned mode)
++{
++	return -ENOSYS;
++}
++
+ static inline int gpio_get_value(unsigned gpio)
+ {
+ 	/* GPIO can never have been requested or set as {in,out}put */
+diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
+index fb0fde686cb1..17f5f187699b 100644
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -122,6 +122,8 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
+ 
+ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
+ 
++int gpiod_set_drive(struct gpio_desc *desc, unsigned mode);
++
+ int gpiod_is_active_low(const struct gpio_desc *desc);
+ int gpiod_cansleep(const struct gpio_desc *desc);
+ 
+@@ -376,6 +378,15 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
+ 	return -ENOSYS;
+ }
+ 
++
++static inline int gpiod_set_drive(unsigned gpio, unsigned mode)
++{
++	/* GPIO can never have been requested */
++	WARN_ON(1);
++	return -ENOSYS;
++}
++
++
+ static inline int gpiod_is_active_low(const struct gpio_desc *desc)
+ {
+ 	/* GPIO can never have been requested */
+diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
+index de502c7e4171..d59080ba9fec 100644
+--- a/include/linux/gpio/driver.h
++++ b/include/linux/gpio/driver.h
+@@ -116,6 +116,8 @@ struct gpio_chip {
+ 	int			(*set_debounce)(struct gpio_chip *chip,
+ 						unsigned offset,
+ 						unsigned debounce);
++	int			(*set_drive)(struct gpio_chip *chip,
++						unsigned offset, unsigned mode);
+ 
+ 	int			(*to_irq)(struct gpio_chip *chip,
+ 						unsigned offset);
+-- 
+2.16.4
+

+ 105 - 0
board/PSG/iot2000/linux-4.4-patches_orig/linux-4.4-patches/0018-iot2000-hack-pwm-pca-9685-Provide-chip-level-pwm_per.patch

@@ -0,0 +1,105 @@
+From c25a8e605bcbb0ed2adde384587ffcfcf5783eef Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Fri, 17 Nov 2017 20:25:54 +0100
+Subject: [PATCH 18/18] iot2000-hack: pwm: pca-9685: Provide chip-level
+ pwm_period attribute
+
+Arduino runtime relies on this path to program the PWM period, rather
+than doing this via the upstream kernel API which is per channel.
+
+Another one not for upstream.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ drivers/pwm/pwm-pca9685.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+
+diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
+index 611b9263a896..ce765f903714 100644
+--- a/drivers/pwm/pwm-pca9685.c
++++ b/drivers/pwm/pwm-pca9685.c
+@@ -444,6 +444,54 @@ static const struct pwm_ops pca9685_pwm_ops = {
+ 	.owner = THIS_MODULE,
+ };
+ 
++static ssize_t pwm_period_show(struct device *parent,
++			       struct device_attribute *attr,
++			       char *buf)
++{
++	struct pwm_chip *chip = dev_get_drvdata(parent);
++
++	return sprintf(buf, "%u\n", to_pca(chip)->period_ns);
++}
++
++static ssize_t pwm_period_store(struct device *parent,
++				struct device_attribute *attr,
++				const char *buf, size_t size)
++{
++	struct pwm_chip *chip = dev_get_drvdata(parent);
++	struct pca9685 *pca = to_pca(chip);
++	int old_period_ns = pca->period_ns;
++	unsigned long long duty_scale, new_duty_ns;
++	unsigned int val, channel;
++	struct pwm_device *pwm;
++	int ret;
++
++	ret = kstrtouint(buf, 0, &val);
++	if (ret)
++		return ret;
++
++	for (channel = 0; channel < PCA9685_MAXCHAN; channel++) {
++		pwm = &chip->pwms[channel];
++
++		if (pca9685_pwm_is_gpio(pca, pwm))
++			continue;
++
++		/* Scale the rise time to maintain duty cycle */
++		duty_scale = val;
++		duty_scale *= 1000000;
++		do_div(duty_scale, old_period_ns);
++		new_duty_ns = duty_scale * pwm_get_duty_cycle(pwm);
++		do_div(new_duty_ns, 1000000);
++		/* Update the duty_cycle */
++		ret = pwm_config(pwm, (int)new_duty_ns, val);
++		if (ret)
++			return ret;
++	}
++
++	return size;
++}
++
++static DEVICE_ATTR_RW(pwm_period);
++
+ static const struct regmap_config pca9685_regmap_i2c_config = {
+ 	.reg_bits = 8,
+ 	.val_bits = 8,
+@@ -504,8 +552,17 @@ static int pca9685_pwm_probe(struct i2c_client *client,
+ 	if (ret < 0)
+ 		return ret;
+ 
++	ret = sysfs_create_file(&pca->chip.dev->kobj,
++				&dev_attr_pwm_period.attr);
++	if (ret < 0) {
++		pwmchip_remove(&pca->chip);
++		return ret;
++	}
++
+ 	ret = pca9685_pwm_gpio_probe(pca);
+ 	if (ret < 0) {
++		sysfs_remove_file(&pca->chip.dev->kobj,
++				  &dev_attr_pwm_period.attr);
+ 		pwmchip_remove(&pca->chip);
+ 		return ret;
+ 	}
+@@ -526,6 +583,8 @@ static int pca9685_pwm_remove(struct i2c_client *client)
+ 	struct pca9685 *pca = i2c_get_clientdata(client);
+ 	int ret;
+ 
++	sysfs_remove_file(&pca->chip.dev->kobj, &dev_attr_pwm_period.attr);
++
+ 	ret = pwmchip_remove(&pca->chip);
+ 	if (ret)
+ 		return ret;
+-- 
+2.16.4
+

BIN
board/PSG/iot2000/rootfs_overlay/lib/libsnap7.so


+ 1 - 1
configs/iot2000_defconfig

@@ -27,7 +27,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="../PSG/board/PSG/iot2000/post-build.sh"
 BR2_ROOTFS_POST_IMAGE_SCRIPT="../PSG/board/PSG/iot2000/post-image.sh"
 BR2_LINUX_KERNEL=y
 BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip.git/snapshot/linux-cip-4.4.185-cip35-rt24.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip.git/snapshot/linux-cip-4.4.208-cip41.tar.gz"
 BR2_LINUX_KERNEL_PATCH="../PSG/board/PSG/iot2000/linux-4.4-patches"
 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="../PSG/board/PSG/iot2000/linux-4.4.config"

+ 6 - 0
package/Snap7/Config.in

@@ -0,0 +1,6 @@
+config BR2_PACKAGE_SNAP7
+	bool "snap7"
+	default y
+	help
+		library to acces S7 (SIEMENS PLS) data
+

+ 24 - 0
package/Snap7/Snap7.mk

@@ -0,0 +1,24 @@
+SNAP7_VERSION:=  b118aefdc184bda1a62c5527424696dbd28bdf05
+SNAP7_SITE:= https://gogs.psg-bgh.de/PSG/snap7-iot-quark-1.4.2.git
+SNAP7_SITE_METHOD:= git
+SNAP7_INSTALL_TARGET:=YES
+SNAP7_INSTALL_STAGING:=YES
+
+define SNAP7_BUILD_CMDS
+	echo `basedir $(TARGET_CC)`
+	echo "============================================="
+	printenv
+	echo "============================================="
+	$(MAKE) -f ./i586_linux.mk CROSS_COMPILE="$(TARGET_CROSS)" -C $(@D)/build/unix all
+endef
+
+define SNAP7_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0755 $(@D)/build/bin/i586-linux/libsnap7.so $(TARGET_DIR)/lib
+endef
+
+define SNAP7_INSTALL_STAGING_CMDS
+	$(INSTALL) -D -m 0755 $(@D)/build/bin/i586-linux/libsnap7.so $(STAGING_DIR)/lib
+endef
+
+
+$(eval $(generic-package))

+ 98 - 0
patches/007-modifications-CrossCompile-Toolchain.patch

@@ -0,0 +1,98 @@
+diff --git a/CrossCompile.sh b/CrossCompile.sh
+index cd87200..a94e25a 100755
+--- a/CrossCompile.sh
++++ b/CrossCompile.sh
+@@ -6,29 +6,83 @@ WRKDIR=`pwd`
+ CMDDIR=`dirname $0`
+ cd $CMDDIR
+ 
++#=== Asssign GNU_TARGET_NAME from .config
++_ARCH=`grep BR2_ARCH\= .config | awk -F\= -F\" '{print $2}'`
++_TARGET_VENDOR=`grep BR2_TOOLCHAIN_BUILDROOT_VENDOR\= .config | awk -F\= -F\" '{print $2}'`
++
++# -- get target os
++_BR2_BINFMT_FLAT=`grep BR2_BINFMT_FLAT\= .config | awk -F\= '{print $2}'`
++if [ "$_BR2_BINFMT_FLAT" = "y" ]; then
++	_TARGET_OS="uclinux"
++	else
++	_TARGET_OS="linux"
++fi	
++
++# -- get libc
++_BR2_TOOLCHAIN_USES_UCLIBC=`grep BR2_TOOLCHAIN_USES_UCLIBC\= .config | awk -F\= '{print $2}'`
++_BR2_TOOLCHAIN_USES_MUSL=`grep BR2_TOOLCHAIN_USES_MUSL\= .config | awk -F\= '{print $2}'`
++
++if [ "$_BR2_TOOLCHAIN_USES_UCLIBC" = "y" ]; then
++	_LIBC="uclibc"
++	else
++	if [ "$_BR2_TOOLCHAIN_USES_MUSL" = "y" ]; then
++		_LIBC="musl"
++		else
++		_LIBC="gnu"
++	fi
++fi	 		
++
++# -- ABI
++_BR2_arm=`grep BR2_arm\= .config | awk -F\= '{print $2}'`
++_BR2_armeb=`grep BR2_armeb\= .config | awk -F\= '{print $2}'`
++_BR2_ARM_EABIHF=`grep BR2_ARM_EABIHF\= .config | awk -F\= '{print $2}'`
++if [ "$_BR2_arm" = "y" ] || [ "$_BR2_armeb" = "y" ]; then
++	if [ "$_LIBC" = "uclibc" ]; then
++		_ABI="gnueabi"
++		else
++		_ABI="eabi"
++	fi
++	if [ "$_BR2_ARM_EABIHF" = "y" ]; then
++		_ABI="${_ABI}hf"
++	fi
++fi
++	
++_GNU_TARGET_NAME="${_ARCH}-${_TARGET_VENDOR}-${_TARGET_OS}-${_LIBC}${_ABI}"
++#===============================================================
++
+ TOOLCHAIN=`grep BR2_HOST_DIR .config | awk -F\= -F\" '{print $2}'`
+ echo $TOOLCHAIN
+ 
+ if [[ $TOOLCHAIN = *\$\(BASE_DIR\)* ]]; then
+-	export SYSROOTBIN=`readlink -f $CMDDIR`/output/host/usr/bin/
++	export SYSROOT=`readlink -f $CMDDIR`/output/host/usr/bin/
+ else
+-	export SYSROOTBIN=$TOOLCHAIN/usr/bin
++	export SYSROOT=$TOOLCHAIN/usr/bin
+ fi
+ 
+-export PATH=$PATH:$SYSROOTBIN
++export PATH=$PATH:$SYSROOT
++
++export CROSS_COMPILE="${_GNU_TARGET_NAME}-"
++export CROSS=${CROSS_COMPILE}
+ 
+-export CROSS_COMPILE=i586-buildroot-linux-gnu-
+-export CROSS=$CROSS_COMPILE
+-export ARCH=i586
+-export KERNELDIR=`pwd`/output/build/linux-linux-4.4.y
++export ARCH=arm
++_KERNELDIR=`grep BR2_LINUX_KERNEL_VERSION\= .config | awk -F\= -F\" '{print $2}'`
++export KERNELDIR=${CMDDIR}/output/build/linux-${_KERNELDIR}
+ export BB_KERNEL_SOURCES=$KERNELDIR
+-export SYSROOT=`grep BR2_HOST_DIR .config | awk -F\= -F\" '{print $2}'`/usr/i586-buildroot-linux-gnu/sysroot
+-export CC_FULLPATH="${SYSROOTBIN}${CROSS_COMPILE}"
++export SYSROOTARM=`grep BR2_HOST_DIR .config | awk -F\= -F\" '{print $2}'`/usr/${_GNU_TARGET_NAME}/sysroot
++export CC_FULLPATH="${SYSROOT}/${CROSS_COMPILE}"
+ export CC=${CROSS_COMPILE}gcc
+ export CXX=${CROSS_COMPILE}g++
+ 
++#--- gnupru
++export PASM=pasm
++##export PSYSROOT=/home/ru/pru/pru-gcc/bin
++export PSYSROOT=/opt/GfA/PRU-ICSS/bin/pru-gcc/bin
++export PATH=$PSYSROOT:$PATH
++
++export PCROSS_COMPILE=pru-
++export PARCH=pru
++
+ cd $WRKDIR
+-echo $CROSS_COMPILE
+ if [ $# -eq "0" ] 
+ then
+ PROMPT_COMMAND='PS1="\[\033[0;31m\]CROSS CC:\[\033[0;32m\]$PS1";unset PROMPT_COMMAND' bash ; reset