kernel: Update 4.10 tree
Move to 4.10.17. This incorporates all of the 4.10 stable fixes. 4.10 is
now end of lifed and does not receive further fixes.
New drivers:
- LPC snoop
- OCC SBE
- SBE FIFO
- Infineon IR35221
- Maxim MAX31785
- of_serial reset support
- Aspeed PWM and fan tach driver
- UCHI driver
- FSI device tree match support
New platforms:
- Mellanox MSN BMC
Config and device tree changes:
- Enable VMSPLIT_2G for ast2400. This is allows us to map all of the
mtd flash
- Fix device trees for ast2400 mtd support
Resolves openbmc/openbmc#1686
- Add CFAM layout to device tree
Resolves openbmc/openbmc#1697
- Enable new drivers
[the content below is for the changes made in c13af44db76bd1 and are
included so that the details are in openbmc history]
This is OpenBMC's third major kernel change. We now move to a 4.10 base,
where a larger amount of our driver support has been upstreamed.
- NCSI stack
- IRQ driver
- Watchdog driver
- Clocksource driver
- GPIO driver
- Pinmux driver
- ftgmac100 ast2500 support
- IPMI BT driver
- adm1275 driver fix
In addition, this contains backports of a significant amount of work
that was done post-4.10.
- LPC bindings
- Pinctrl enhancements
- Flash controller (spi-nor) basic support
- ast2500 GPIO support
- LPC host interface controller driver
- Aspeed ADC
- GPIO debounce support
- Pinconf (biasing and drive strength) driver
Finally, there is the work-in-progress that has been temporarly staged
in the dev tree while we get it reviewed and upstreamed.
- New I2C driver
- OCC driver
- LPC mailbox driver
- FSI core
- VUART driver
Defconfig updates
- Optmise options for network performance
- Update for upstreamed drivers (MTD driver was renamed, etc)
- Enable drivers that are in use
Legacy Yocto layer changes
- Remove palmetto GPIO hog patch. It is in the kenrel tree
Change-Id: I4b48b843572c8f8d547763f0d3cb5a6742bbf0e3
Signed-off-by: Joel Stanley <joel@jms.id.au>
diff --git a/common/recipes-kernel/linux/linux-obmc.inc b/common/recipes-kernel/linux/linux-obmc.inc
index fe07680..78da469 100644
--- a/common/recipes-kernel/linux/linux-obmc.inc
+++ b/common/recipes-kernel/linux/linux-obmc.inc
@@ -10,18 +10,6 @@
SRC_URI = "${KSRC}"
SRC_URI += "file://phosphor-gpio-keys.scc"
SRC_URI += "file://phosphor-gpio-keys.cfg"
-SRC_URI += "file://0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch"
-SRC_URI += "file://linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch"
-SRC_URI += "file://linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch"
-SRC_URI += "file://linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch"
-SRC_URI += "file://linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch"
-SRC_URI += "file://linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch"
-SRC_URI += "file://linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch"
-SRC_URI += "file://linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch"
-SRC_URI += "file://linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch"
-SRC_URI += "file://0001-arm-dts-aspeed-Add-FSI-devices.patch"
-SRC_URI += "file://0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch"
-SRC_URI += "file://v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch"
LINUX_VERSION_EXTENSION ?= "-${SRCREV}"
diff --git a/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch b/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch
deleted file mode 100644
index 3b49685..0000000
--- a/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch
+++ /dev/null
@@ -1,507 +0,0 @@
-From e45cd4677a36eb759537f59c5f5bcf46b91728b3 Mon Sep 17 00:00:00 2001
-From: "Edward A. James" <eajames@us.ibm.com>
-Date: Mon, 15 May 2017 11:02:48 -0500
-Subject: [PATCH linux dev-4.10] arm: dts: aspeed: Add FSI devices
-
-using Jeremy's new bindings
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts | 75 ++++++++++
- arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 181 +++++++++++++++++++++++
- arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts | 181 +++++++++++++++++++++++
- 3 files changed, 437 insertions(+)
-
-diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-index b4faa1d..6f23ce3 100644
---- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-@@ -85,12 +85,87 @@
-
- gpio-fsi {
- compatible = "fsi-master-gpio", "fsi-master";
-+ #address-cells = <2>;
-+ #size-cells = <0>;
-
- clock-gpios = <&gpio ASPEED_GPIO(A, 4) GPIO_ACTIVE_HIGH>;
- data-gpios = <&gpio ASPEED_GPIO(A, 5) GPIO_ACTIVE_HIGH>;
- mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>;
- enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
- trans-gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_HIGH>;
-+
-+ cfam@0,0 {
-+ reg = <0 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ i2c-master@1800 {
-+ compatible = "ibm,fsi-i2c-master";
-+ reg = <0x1800 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ port = <0>;
-+ };
-+
-+ port@1 {
-+ port = <1>;
-+ };
-+
-+ port@2 {
-+ port = <2>;
-+ };
-+
-+ port@3 {
-+ port = <3>;
-+ };
-+
-+ port@4 {
-+ port = <4>;
-+ };
-+
-+ port@5 {
-+ port = <5>;
-+ };
-+
-+ port@6 {
-+ port = <6>;
-+ };
-+
-+ port@7 {
-+ port = <7>;
-+ };
-+
-+ port@8 {
-+ port = <8>;
-+ };
-+
-+ port@9 {
-+ port = <9>;
-+ };
-+
-+ port@10 {
-+ port = <10>;
-+ };
-+
-+ port@11 {
-+ port = <11>;
-+ };
-+
-+ port@12 {
-+ port = <12>;
-+ };
-+
-+ port@13 {
-+ port = <13>;
-+ };
-+
-+ port@14 {
-+ port = <14>;
-+ };
-+ };
-+ };
- };
- };
-
-diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
-index f20aaf4..5d83a76 100644
---- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
-+++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
-@@ -65,6 +65,8 @@
-
- gpio-fsi {
- compatible = "fsi-master-gpio", "fsi-master";
-+ #address-cells = <2>;
-+ #size-cells = <0>;
-
- status = "okay";
-
-@@ -73,6 +75,185 @@
- mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>;
- enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
- trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
-+
-+ cfam@0,0 {
-+ reg = <0 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ i2c-master@1800 {
-+ compatible = "ibm,fsi-i2c-master";
-+ reg = <0x1800 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ port = <0>;
-+ };
-+
-+ port@1 {
-+ port = <1>;
-+ };
-+
-+ port@2 {
-+ port = <2>;
-+ };
-+
-+ port@3 {
-+ port = <3>;
-+ };
-+
-+ port@4 {
-+ port = <4>;
-+ };
-+
-+ port@5 {
-+ port = <5>;
-+ };
-+
-+ port@6 {
-+ port = <6>;
-+ };
-+
-+ port@7 {
-+ port = <7>;
-+ };
-+
-+ port@8 {
-+ port = <8>;
-+ };
-+
-+ port@9 {
-+ port = <9>;
-+ };
-+
-+ port@10 {
-+ port = <10>;
-+ };
-+
-+ port@11 {
-+ port = <11>;
-+ };
-+
-+ port@12 {
-+ port = <12>;
-+ };
-+
-+ port@13 {
-+ port = <13>;
-+ };
-+
-+ port@14 {
-+ port = <14>;
-+ };
-+ };
-+
-+ sbefifo@2400 {
-+ compatible = "ibm,p9-sbefifo";
-+ reg = <0x2400 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ occ@1 {
-+ compatible = "ibm,p9-occ";
-+ reg = <1>;
-+ };
-+ };
-+
-+ hub@3400 {
-+ compatible = "fsi-master-hub";
-+ reg = <0x3400 0x400>;
-+ #address-cells = <2>;
-+ #size-cells = <0>;
-+
-+ cfam@1,0 {
-+ reg = <1 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ i2c-master@1800 {
-+ compatible =
-+ "ibm,fsi-i2c-master";
-+ reg = <0x1800 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ port = <0>;
-+ };
-+
-+ port@1 {
-+ port = <1>;
-+ };
-+
-+ port@2 {
-+ port = <2>;
-+ };
-+
-+ port@3 {
-+ port = <3>;
-+ };
-+
-+ port@4 {
-+ port = <4>;
-+ };
-+
-+ port@5 {
-+ port = <5>;
-+ };
-+
-+ port@6 {
-+ port = <6>;
-+ };
-+
-+ port@7 {
-+ port = <7>;
-+ };
-+
-+ port@8 {
-+ port = <8>;
-+ };
-+
-+ port@9 {
-+ port = <9>;
-+ };
-+
-+ port@10 {
-+ port = <10>;
-+ };
-+
-+ port@11 {
-+ port = <11>;
-+ };
-+
-+ port@12 {
-+ port = <12>;
-+ };
-+
-+ port@13 {
-+ port = <13>;
-+ };
-+
-+ port@14 {
-+ port = <14>;
-+ };
-+ };
-+
-+ sbefifo@2400 {
-+ compatible = "ibm,p9-sbefifo";
-+ reg = <0x2400 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ occ@2 {
-+ compatible =
-+ "ibm,p9-occ";
-+ reg = <2>;
-+ };
-+ };
-+ };
-+ };
-+ };
- };
-
- iio-hwmon {
-diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
-index b5c4c0f..6f36e56 100644
---- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
-+++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
-@@ -77,6 +77,8 @@
-
- gpio-fsi {
- compatible = "fsi-master-gpio", "fsi-master";
-+ #address-cells = <2>;
-+ #size-cells = <0>;
-
- status = "okay";
-
-@@ -85,6 +87,185 @@
- trans-gpios = <&gpio ASPEED_GPIO(O, 6) GPIO_ACTIVE_HIGH>;
- enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
- mux-gpios = <&gpio ASPEED_GPIO(P, 6) GPIO_ACTIVE_HIGH>;
-+
-+ cfam@0,0 {
-+ reg = <0 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ i2c-master@1800 {
-+ compatible = "ibm,fsi-i2c-master";
-+ reg = <0x1800 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ port = <0>;
-+ };
-+
-+ port@1 {
-+ port = <1>;
-+ };
-+
-+ port@2 {
-+ port = <2>;
-+ };
-+
-+ port@3 {
-+ port = <3>;
-+ };
-+
-+ port@4 {
-+ port = <4>;
-+ };
-+
-+ port@5 {
-+ port = <5>;
-+ };
-+
-+ port@6 {
-+ port = <6>;
-+ };
-+
-+ port@7 {
-+ port = <7>;
-+ };
-+
-+ port@8 {
-+ port = <8>;
-+ };
-+
-+ port@9 {
-+ port = <9>;
-+ };
-+
-+ port@10 {
-+ port = <10>;
-+ };
-+
-+ port@11 {
-+ port = <11>;
-+ };
-+
-+ port@12 {
-+ port = <12>;
-+ };
-+
-+ port@13 {
-+ port = <13>;
-+ };
-+
-+ port@14 {
-+ port = <14>;
-+ };
-+ };
-+
-+ sbefifo@2400 {
-+ compatible = "ibm,p9-sbefifo";
-+ reg = <0x2400 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ occ@1 {
-+ compatible = "ibm,p9-occ";
-+ reg = <1>;
-+ };
-+ };
-+
-+ hub@3400 {
-+ compatible = "fsi-master-hub";
-+ reg = <0x3400 0x400>;
-+ #address-cells = <2>;
-+ #size-cells = <0>;
-+
-+ cfam@1,0 {
-+ reg = <1 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ i2c-master@1800 {
-+ compatible =
-+ "ibm,fsi-i2c-master";
-+ reg = <0x1800 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ port = <0>;
-+ };
-+
-+ port@1 {
-+ port = <1>;
-+ };
-+
-+ port@2 {
-+ port = <2>;
-+ };
-+
-+ port@3 {
-+ port = <3>;
-+ };
-+
-+ port@4 {
-+ port = <4>;
-+ };
-+
-+ port@5 {
-+ port = <5>;
-+ };
-+
-+ port@6 {
-+ port = <6>;
-+ };
-+
-+ port@7 {
-+ port = <7>;
-+ };
-+
-+ port@8 {
-+ port = <8>;
-+ };
-+
-+ port@9 {
-+ port = <9>;
-+ };
-+
-+ port@10 {
-+ port = <10>;
-+ };
-+
-+ port@11 {
-+ port = <11>;
-+ };
-+
-+ port@12 {
-+ port = <12>;
-+ };
-+
-+ port@13 {
-+ port = <13>;
-+ };
-+
-+ port@14 {
-+ port = <14>;
-+ };
-+ };
-+
-+ sbefifo@2400 {
-+ compatible = "ibm,p9-sbefifo";
-+ reg = <0x2400 0x400>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ occ@2 {
-+ compatible =
-+ "ibm,p9-occ";
-+ reg = <2>;
-+ };
-+ };
-+ };
-+ };
-+ };
- };
-
- iio-hwmon {
---
-1.8.3.1
-
diff --git a/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch b/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch
deleted file mode 100644
index 6fdfe93..0000000
--- a/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch
+++ /dev/null
@@ -1,236 +0,0 @@
-From 8f10daa0cc99ce286b9a2f249f1fa0a245d4fc03 Mon Sep 17 00:00:00 2001
-From: "Edward A. James" <eajames@us.ibm.com>
-Date: Wed, 17 May 2017 09:46:19 -0500
-Subject: [PATCH] fsi: Match fsi slaves & engines to available device tree
- nodes
-
-This change populates device tree nodes for scanned FSI slaves and
-engines. If the master populates ->of_node of the FSI master device,
-we'll look for matching slaves, and under those slaves we'll look for
-matching engines.
-
-This means that FSI drivers will have their ->of_node pointer populated
-if there's a corresponding DT node, which they can use for further
-device discover.
-
-Presence of device tree nodes is optional, and only required for
-fsi device drivers that need extra properties, or subordinate devices,
-to be enumerated.
-
-Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/fsi/fsi-core.c | 99 +++++++++++++++++++++++++++++++++++++++++++
- drivers/fsi/fsi-master-gpio.c | 4 ++
- drivers/fsi/fsi-master-hub.c | 4 ++
- 3 files changed, 107 insertions(+)
-
-diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
-index 7ca5b74..71e3af9 100644
---- a/drivers/fsi/fsi-core.c
-+++ b/drivers/fsi/fsi-core.c
-@@ -17,6 +17,7 @@
- #include <linux/fsi.h>
- #include <linux/idr.h>
- #include <linux/module.h>
-+#include <linux/of.h>
- #include <linux/slab.h>
-
- #include "fsi-master.h"
-@@ -125,6 +126,7 @@ static void fsi_device_release(struct device *_device)
- {
- struct fsi_device *device = to_fsi_dev(_device);
-
-+ of_node_put(device->dev.of_node);
- kfree(device);
- }
-
-@@ -337,6 +339,57 @@ extern void fsi_slave_release_range(struct fsi_slave *slave,
- {
- }
-
-+static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
-+ uint32_t addr, uint32_t size)
-+{
-+ unsigned int len, na, ns;
-+ const __be32 *prop;
-+ uint32_t psize;
-+
-+ na = of_n_addr_cells(np);
-+ ns = of_n_size_cells(np);
-+
-+ if (na != 1 || ns != 1)
-+ return false;
-+
-+ prop = of_get_property(np, "reg", &len);
-+ if (!prop || len != 8)
-+ return false;
-+
-+ if (of_read_number(prop, 1) != addr)
-+ return false;
-+
-+ psize = of_read_number(prop + 1, 1);
-+ if (psize != size) {
-+ dev_warn(dev,
-+ "node %s matches probed address, but not size (got 0x%x, expected 0x%x)",
-+ of_node_full_name(np), psize, size);
-+ }
-+
-+ return true;
-+}
-+
-+/* Find a matching node for the slave engine at @address, using @size bytes
-+ * of space. Returns NULL if not found, or a matching node with refcount
-+ * already incremented.
-+ */
-+static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
-+{
-+ struct device_node *parent, *np;
-+
-+ parent = dev_of_node(&dev->slave->dev);
-+ if (!parent)
-+ return NULL;
-+
-+ for_each_child_of_node(parent, np) {
-+ if (fsi_device_node_matches(&dev->dev, np,
-+ dev->addr, dev->size))
-+ return np;
-+ }
-+
-+ return NULL;
-+}
-+
- static int fsi_slave_scan(struct fsi_slave *slave)
- {
- uint32_t engine_addr;
-@@ -405,6 +458,7 @@ static int fsi_slave_scan(struct fsi_slave *slave)
- dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
- slave->master->idx, slave->link,
- slave->id, i - 2);
-+ dev->dev.of_node = fsi_device_find_of_node(dev);
-
- rc = device_register(&dev->dev);
- if (rc) {
-@@ -561,9 +615,53 @@ static void fsi_slave_release(struct device *dev)
- {
- struct fsi_slave *slave = to_fsi_slave(dev);
-
-+ of_node_put(dev->of_node);
- kfree(slave);
- }
-
-+static bool fsi_slave_node_matches(struct device_node *np,
-+ int link, uint8_t id)
-+{
-+ unsigned int len, na, ns;
-+ const __be32 *prop;
-+
-+ na = of_n_addr_cells(np);
-+ ns = of_n_size_cells(np);
-+
-+ /* Ensure we have the correct format for addresses and sizes in
-+ * reg properties
-+ */
-+ if (na != 2 || ns != 0)
-+ return false;
-+
-+ prop = of_get_property(np, "reg", &len);
-+ if (!prop || len != 8)
-+ return false;
-+
-+ return (of_read_number(prop, 1) == link) &&
-+ (of_read_number(prop + 1, 1) == id);
-+}
-+
-+/* Find a matching node for the slave at (link, id). Returns NULL if none
-+ * found, or a matching node with refcount already incremented.
-+ */
-+static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
-+ int link, uint8_t id)
-+{
-+ struct device_node *parent, *np;
-+
-+ parent = dev_of_node(&master->dev);
-+ if (!parent)
-+ return NULL;
-+
-+ for_each_child_of_node(parent, np) {
-+ if (fsi_slave_node_matches(np, link, id))
-+ return np;
-+ }
-+
-+ return NULL;
-+}
-+
- static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
- {
- uint32_t chip_id, llmode;
-@@ -626,6 +724,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
-
- slave->master = master;
- slave->dev.parent = &master->dev;
-+ slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
- slave->dev.release = fsi_slave_release;
- slave->link = link;
- slave->id = id;
-diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
-index ef209ef..2a6a812 100644
---- a/drivers/fsi/fsi-master-gpio.c
-+++ b/drivers/fsi/fsi-master-gpio.c
-@@ -5,6 +5,7 @@
- #include <linux/platform_device.h>
- #include <linux/gpio/consumer.h>
- #include <linux/module.h>
-+#include <linux/of.h>
- #include <linux/delay.h>
- #include <linux/fsi.h>
- #include <linux/device.h>
-@@ -529,6 +530,7 @@ static int fsi_master_gpio_probe(struct platform_device *pdev)
-
- master->dev = &pdev->dev;
- master->master.dev.parent = master->dev;
-+ master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
- master->master.dev.release = fsi_master_gpio_release;
-
- gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
-@@ -598,6 +600,8 @@ static int fsi_master_gpio_remove(struct platform_device *pdev)
- devm_gpiod_put(&pdev->dev, master->gpio_mux);
- fsi_master_unregister(&master->master);
-
-+ of_node_put(master->master.dev.of_node);
-+
- return 0;
- }
-
-diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
-index 133b9bf..3223a67 100644
---- a/drivers/fsi/fsi-master-hub.c
-+++ b/drivers/fsi/fsi-master-hub.c
-@@ -16,6 +16,7 @@
- #include <linux/delay.h>
- #include <linux/fsi.h>
- #include <linux/module.h>
-+#include <linux/of.h>
- #include <linux/slab.h>
-
- #include "fsi-master.h"
-@@ -274,6 +275,7 @@ static int hub_master_probe(struct device *dev)
-
- hub->master.dev.parent = dev;
- hub->master.dev.release = hub_master_release;
-+ hub->master.dev.of_node = of_node_get(dev_of_node(dev));
-
- hub->master.n_links = links;
- hub->master.read = hub_master_read;
-@@ -302,6 +304,8 @@ static int hub_master_remove(struct device *dev)
-
- fsi_master_unregister(&hub->master);
- fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size);
-+ of_node_put(hub->master.dev.of_node);
-+
- return 0;
- }
-
---
-1.8.3.1
-
diff --git a/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch b/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch
deleted file mode 100644
index 8ade1be..0000000
--- a/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch
+++ /dev/null
@@ -1,821 +0,0 @@
-From b3991e27b26930ef46206dad17715d8ac2f38a4e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <tpearson@raptorengineering.com>
-Date: Tue, 11 Oct 2016 09:35:51 -0500
-Subject: [PATCH] hwmon: Add support for MAX31785 intelligent fan controller
-
-Add a basic driver for the MAX31785, focusing on the fan control
-features but ignoring the temperature and voltage monitoring
-features of the device.
-
-This driver supports all fan control modes and tachometer / PWM
-readback where applicable.
-
-Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com>
-Signed-off-by: Joel Stanley <joel@jms.id.au>
----
- Documentation/hwmon/max31785 | 36 +++
- drivers/hwmon/Kconfig | 10 +
- drivers/hwmon/Makefile | 1 +
- drivers/hwmon/max31785.c | 714 +++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 761 insertions(+)
- create mode 100644 Documentation/hwmon/max31785
- create mode 100644 drivers/hwmon/max31785.c
-
-diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785
-new file mode 100644
-index 0000000..0911d20
---- /dev/null
-+++ b/Documentation/hwmon/max31785
-@@ -0,0 +1,36 @@
-+Kernel driver max31785
-+======================
-+
-+Supported chips:
-+ * Maxim MAX31785
-+ Prefix: 'max31785'
-+ Addresses scanned: 0x52 0x53 0x54 0x55
-+ Datasheet: http://pdfserv.maximintegrated.com/en/ds/MAX31785.pdf
-+
-+Author: Timothy Pearson <tpearson@raptorengineering.com>
-+
-+
-+Description
-+-----------
-+
-+This driver implements support for the Maxim MAX31785 chip.
-+
-+The MAX31785 controls the speeds of up to six fans using six independent
-+PWM outputs. The desired fan speeds (or PWM duty cycles) are written
-+through the I2C interface. The outputs drive "4-wire" fans directly,
-+or can be used to modulate the fan's power terminals using an external
-+pass transistor.
-+
-+Tachometer inputs monitor fan tachometer logic outputs for precise (+/-1%)
-+monitoring and control of fan RPM as well as detection of fan failure.
-+
-+
-+Sysfs entries
-+-------------
-+
-+fan[1-6]_input RO fan tachometer speed in RPM
-+fan[1-6]_fault RO fan experienced fault
-+fan[1-6]_pulses RW tachometer pulses per fan revolution
-+fan[1-6]_target RW desired fan speed in RPM
-+pwm[1-6]_enable RW pwm mode, 0=disabled, 1=pwm, 2=rpm, 3=automatic
-+pwm[1-6] RW fan target duty cycle (0-255)
-diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
-index 190d270..136605d 100644
---- a/drivers/hwmon/Kconfig
-+++ b/drivers/hwmon/Kconfig
-@@ -886,6 +886,16 @@ config SENSORS_MAX6697
- This driver can also be built as a module. If so, the module
- will be called max6697.
-
-+config SENSORS_MAX31785
-+ tristate "Maxim MAX31785 sensor chip"
-+ depends on I2C
-+ help
-+ If you say yes here you get support for 6-Channel PWM-Output
-+ Fan RPM Controller.
-+
-+ This driver can also be built as a module. If so, the module
-+ will be called max31785.
-+
- config SENSORS_MAX31790
- tristate "Maxim MAX31790 sensor chip"
- depends on I2C
-diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
-index d2cb7e8..e8ba5c6 100644
---- a/drivers/hwmon/Makefile
-+++ b/drivers/hwmon/Makefile
-@@ -119,6 +119,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
- obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
- obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
- obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
-+obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
- obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
- obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
- obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
-diff --git a/drivers/hwmon/max31785.c b/drivers/hwmon/max31785.c
-new file mode 100644
-index 0000000..fb7b3f0
---- /dev/null
-+++ b/drivers/hwmon/max31785.c
-@@ -0,0 +1,714 @@
-+/*
-+ * max31785.c - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring.
-+ *
-+ * (C) 2016 Raptor Engineering, LLC
-+ *
-+ * 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.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/hwmon.h>
-+#include <linux/hwmon-sysfs.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/jiffies.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+
-+/* MAX31785 device IDs */
-+#define MAX31785_MFR_ID 0x4d
-+#define MAX31785_MFR_MODEL 0x53
-+
-+/* MAX31785 registers */
-+#define MAX31785_REG_PAGE 0x00
-+#define MAX31785_PAGE_FAN_CONFIG(ch) (0x00 + (ch))
-+#define MAX31785_REG_FAN_CONFIG_1_2 0x3a
-+#define MAX31785_REG_FAN_COMMAND_1 0x3b
-+#define MAX31785_REG_STATUS_FANS_1_2 0x81
-+#define MAX31785_REG_FAN_SPEED_1 0x90
-+#define MAX31785_REG_MFR_ID 0x99
-+#define MAX31785_REG_MFR_MODEL 0x9a
-+#define MAX31785_REG_MFR_FAN_CONFIG 0xf1
-+#define MAX31785_REG_READ_FAN_PWM 0xf3
-+
-+/* Fan Config register bits */
-+#define MAX31785_FAN_CFG_PWM_ENABLE 0x80
-+#define MAX31785_FAN_CFG_CONTROL_MODE_RPM 0x40
-+#define MAX31785_FAN_CFG_PULSE_MASK 0x30
-+#define MAX31785_FAN_CFG_PULSE_SHIFT 4
-+#define MAX31785_FAN_CFG_PULSE_OFFSET 1
-+
-+/* Fan Status register bits */
-+#define MAX31785_FAN_STATUS_FAULT_MASK 0x80
-+
-+/* Fan Command constants */
-+#define MAX31785_FAN_COMMAND_PWM_RATIO 40
-+
-+#define NR_CHANNEL 6
-+
-+/* Addresses to scan */
-+static const unsigned short normal_i2c[] = { 0x52, 0x53, 0x54, 0x55,
-+ I2C_CLIENT_END };
-+
-+/*
-+ * Client data (each client gets its own)
-+ */
-+struct max31785_data {
-+ struct i2c_client *client;
-+ struct mutex device_lock;
-+ bool valid; /* zero until following fields are valid */
-+ unsigned long last_updated; /* in jiffies */
-+
-+ /* register values */
-+ u8 fan_config[NR_CHANNEL];
-+ u16 fan_command[NR_CHANNEL];
-+ u8 mfr_fan_config[NR_CHANNEL];
-+ u8 fault_status[NR_CHANNEL];
-+ u16 tach_rpm[NR_CHANNEL];
-+ u16 pwm[NR_CHANNEL];
-+};
-+
-+static int max31785_set_page(struct i2c_client *client,
-+ u8 page)
-+{
-+ return i2c_smbus_write_byte_data(client,
-+ MAX31785_REG_PAGE,
-+ page);
-+}
-+
-+static int max31785_read_fan_data(struct i2c_client *client,
-+ u8 fan, u8 reg, u8 byte_mode)
-+{
-+ int rv;
-+
-+ rv = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan));
-+ if (rv < 0)
-+ return rv;
-+
-+ if (byte_mode)
-+ rv = i2c_smbus_read_byte_data(client, reg);
-+ else
-+ rv = i2c_smbus_read_word_data(client, reg);
-+
-+ return rv;
-+}
-+
-+static int max31785_write_fan_data(struct i2c_client *client,
-+ u8 fan, u8 reg, u16 data,
-+ u8 byte_mode)
-+{
-+ int err;
-+
-+ err = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan));
-+ if (err < 0)
-+ return err;
-+
-+ if (byte_mode)
-+ err = i2c_smbus_write_byte_data(client, reg, data);
-+ else
-+ err = i2c_smbus_write_word_data(client, reg, data);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return 0;
-+}
-+
-+static bool is_automatic_control_mode(struct max31785_data *data,
-+ int index)
-+{
-+ if (data->fan_command[index] > 0x7fff)
-+ return true;
-+ else
-+ return false;
-+}
-+
-+static struct max31785_data *max31785_update_device(struct device *dev)
-+{
-+ struct max31785_data *data = dev_get_drvdata(dev);
-+ struct i2c_client *client = data->client;
-+ struct max31785_data *ret = data;
-+ int i;
-+ int rv;
-+
-+ mutex_lock(&data->device_lock);
-+
-+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-+ for (i = 0; i < NR_CHANNEL; i++) {
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_STATUS_FANS_1_2, 1);
-+ if (rv < 0)
-+ goto abort;
-+ data->fault_status[i] = rv;
-+
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_FAN_SPEED_1, 0);
-+ if (rv < 0)
-+ goto abort;
-+ data->tach_rpm[i] = rv;
-+
-+ if ((data->fan_config[i]
-+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM)
-+ || is_automatic_control_mode(data, i)) {
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_READ_FAN_PWM, 0);
-+ if (rv < 0)
-+ goto abort;
-+ data->pwm[i] = rv;
-+ }
-+
-+ if (!is_automatic_control_mode(data, i)) {
-+ /* Poke watchdog for manual fan control */
-+ rv = max31785_write_fan_data(client,
-+ i, MAX31785_REG_FAN_COMMAND_1,
-+ data->fan_command[i], 0);
-+ if (rv < 0)
-+ goto abort;
-+ }
-+ }
-+
-+ data->last_updated = jiffies;
-+ data->valid = true;
-+ }
-+ goto done;
-+
-+abort:
-+ data->valid = false;
-+ ret = ERR_PTR(rv);
-+
-+done:
-+ mutex_unlock(&data->device_lock);
-+
-+ return ret;
-+}
-+
-+static ssize_t get_fan(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ return sprintf(buf, "%d\n", data->tach_rpm[attr->index]);
-+}
-+
-+static ssize_t get_fan_target(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+ int rpm;
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ if (data->fan_config[attr->index]
-+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM)
-+ rpm = data->fan_command[attr->index];
-+ else
-+ rpm = data->fan_command[attr->index]
-+ / MAX31785_FAN_COMMAND_PWM_RATIO;
-+
-+ return sprintf(buf, "%d\n", rpm);
-+}
-+
-+static ssize_t set_fan_target(struct device *dev,
-+ struct device_attribute *devattr,
-+ const char *buf, size_t count)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = dev_get_drvdata(dev);
-+ struct i2c_client *client = data->client;
-+ unsigned long rpm;
-+ int err;
-+
-+ err = kstrtoul(buf, 10, &rpm);
-+ if (err)
-+ return err;
-+
-+ if (rpm > 0x7fff)
-+ return -EINVAL;
-+
-+ mutex_lock(&data->device_lock);
-+
-+ /* Write new RPM value */
-+ data->fan_command[attr->index] = rpm;
-+ err = max31785_write_fan_data(client, attr->index,
-+ MAX31785_REG_FAN_COMMAND_1,
-+ data->fan_command[attr->index], 0);
-+
-+ mutex_unlock(&data->device_lock);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return count;
-+}
-+
-+static ssize_t get_fan_pulses(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+ int pulses;
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ pulses = ((data->fan_config[attr->index] & MAX31785_FAN_CFG_PULSE_MASK)
-+ >> MAX31785_FAN_CFG_PULSE_SHIFT)
-+ + MAX31785_FAN_CFG_PULSE_OFFSET;
-+
-+ return sprintf(buf, "%d\n", pulses);
-+}
-+
-+static ssize_t set_fan_pulses(struct device *dev,
-+ struct device_attribute *devattr,
-+ const char *buf, size_t count)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = dev_get_drvdata(dev);
-+ struct i2c_client *client = data->client;
-+ unsigned long pulses;
-+ int err;
-+
-+ err = kstrtoul(buf, 10, &pulses);
-+ if (err)
-+ return err;
-+
-+ if (pulses > 4)
-+ return -EINVAL;
-+
-+ data->fan_config[attr->index] &= MAX31785_FAN_CFG_PULSE_MASK;
-+ data->fan_config[attr->index] |=
-+ ((pulses - MAX31785_FAN_CFG_PULSE_OFFSET)
-+ << MAX31785_FAN_CFG_PULSE_SHIFT);
-+
-+ mutex_lock(&data->device_lock);
-+
-+ /* Write new pulse value */
-+ data->fan_command[attr->index] = pulses;
-+ err = max31785_write_fan_data(client, attr->index,
-+ MAX31785_REG_FAN_CONFIG_1_2,
-+ data->fan_config[attr->index], 1);
-+
-+ mutex_unlock(&data->device_lock);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return count;
-+}
-+
-+static ssize_t get_pwm(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+ int pwm;
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ if ((data->fan_config[attr->index]
-+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM)
-+ || is_automatic_control_mode(data, attr->index))
-+ pwm = data->pwm[attr->index] / 100;
-+ else
-+ pwm = data->fan_command[attr->index]
-+ / MAX31785_FAN_COMMAND_PWM_RATIO;
-+
-+ return sprintf(buf, "%d\n", pwm);
-+}
-+
-+static ssize_t set_pwm(struct device *dev,
-+ struct device_attribute *devattr,
-+ const char *buf, size_t count)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = dev_get_drvdata(dev);
-+ struct i2c_client *client = data->client;
-+ unsigned long pwm;
-+ int err;
-+
-+ err = kstrtoul(buf, 10, &pwm);
-+ if (err)
-+ return err;
-+
-+ if (pwm > 255)
-+ return -EINVAL;
-+
-+ mutex_lock(&data->device_lock);
-+
-+ /* Write new PWM value */
-+ data->fan_command[attr->index] = pwm * MAX31785_FAN_COMMAND_PWM_RATIO;
-+ err = max31785_write_fan_data(client, attr->index,
-+ MAX31785_REG_FAN_COMMAND_1,
-+ data->fan_command[attr->index], 0);
-+
-+ mutex_unlock(&data->device_lock);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return count;
-+}
-+
-+static ssize_t get_pwm_enable(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+ int mode;
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ if (!(data->fan_config[attr->index] & MAX31785_FAN_CFG_PWM_ENABLE))
-+ mode = 0;
-+ else if (is_automatic_control_mode(data, attr->index))
-+ mode = 3;
-+ else if (data->fan_config[attr->index]
-+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM)
-+ mode = 2;
-+ else
-+ mode = 1;
-+
-+ return sprintf(buf, "%d\n", mode);
-+}
-+
-+static ssize_t set_pwm_enable(struct device *dev,
-+ struct device_attribute *devattr,
-+ const char *buf, size_t count)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = dev_get_drvdata(dev);
-+ struct i2c_client *client = data->client;
-+ unsigned long mode;
-+ int err;
-+
-+ err = kstrtoul(buf, 10, &mode);
-+ if (err)
-+ return err;
-+
-+ switch (mode) {
-+ case 0:
-+ data->fan_config[attr->index] =
-+ data->fan_config[attr->index]
-+ & ~MAX31785_FAN_CFG_PWM_ENABLE;
-+ break;
-+ case 1:
-+ case 2:
-+ case 3:
-+ data->fan_config[attr->index] =
-+ data->fan_config[attr->index]
-+ | MAX31785_FAN_CFG_PWM_ENABLE;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ switch (mode) {
-+ case 0:
-+ break;
-+ case 1:
-+ data->fan_config[attr->index] =
-+ data->fan_config[attr->index]
-+ & ~MAX31785_FAN_CFG_CONTROL_MODE_RPM;
-+ break;
-+ case 2:
-+ data->fan_config[attr->index] =
-+ data->fan_config[attr->index]
-+ | MAX31785_FAN_CFG_CONTROL_MODE_RPM;
-+ break;
-+ case 3:
-+ data->fan_command[attr->index] = 0xffff;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ mutex_lock(&data->device_lock);
-+
-+ err = max31785_write_fan_data(client, attr->index,
-+ MAX31785_REG_FAN_CONFIG_1_2,
-+ data->fan_config[attr->index], 1);
-+
-+ if (err < 0)
-+ goto abort;
-+
-+ err = max31785_write_fan_data(client, attr->index,
-+ MAX31785_REG_FAN_COMMAND_1,
-+ data->fan_command[attr->index], 0);
-+
-+abort:
-+ mutex_unlock(&data->device_lock);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return count;
-+}
-+
-+static ssize_t get_fan_fault(struct device *dev,
-+ struct device_attribute *devattr, char *buf)
-+{
-+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-+ struct max31785_data *data = max31785_update_device(dev);
-+ int fault;
-+
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ fault = !!(data->fault_status[attr->index]
-+ & MAX31785_FAN_STATUS_FAULT_MASK);
-+
-+ return sprintf(buf, "%d\n", fault);
-+}
-+
-+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
-+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
-+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
-+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
-+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, get_fan, NULL, 4);
-+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, get_fan, NULL, 5);
-+
-+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_fault, NULL, 0);
-+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, get_fan_fault, NULL, 1);
-+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, get_fan_fault, NULL, 2);
-+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, get_fan_fault, NULL, 3);
-+static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, get_fan_fault, NULL, 4);
-+static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, get_fan_fault, NULL, 5);
-+
-+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 0);
-+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 1);
-+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 2);
-+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 3);
-+static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 4);
-+static SENSOR_DEVICE_ATTR(fan6_target, S_IWUSR | S_IRUGO,
-+ get_fan_target, set_fan_target, 5);
-+
-+static SENSOR_DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 0);
-+static SENSOR_DEVICE_ATTR(fan2_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 1);
-+static SENSOR_DEVICE_ATTR(fan3_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 2);
-+static SENSOR_DEVICE_ATTR(fan4_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 3);
-+static SENSOR_DEVICE_ATTR(fan5_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 4);
-+static SENSOR_DEVICE_ATTR(fan6_pulses, S_IWUSR | S_IRUGO,
-+ get_fan_pulses, set_fan_pulses, 5);
-+
-+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0);
-+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1);
-+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2);
-+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3);
-+static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 4);
-+static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 5);
-+
-+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 0);
-+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 1);
-+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 2);
-+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 3);
-+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 4);
-+static SENSOR_DEVICE_ATTR(pwm6_enable, S_IWUSR | S_IRUGO,
-+ get_pwm_enable, set_pwm_enable, 5);
-+
-+static struct attribute *max31785_attrs[] = {
-+ &sensor_dev_attr_fan1_input.dev_attr.attr,
-+ &sensor_dev_attr_fan2_input.dev_attr.attr,
-+ &sensor_dev_attr_fan3_input.dev_attr.attr,
-+ &sensor_dev_attr_fan4_input.dev_attr.attr,
-+ &sensor_dev_attr_fan5_input.dev_attr.attr,
-+ &sensor_dev_attr_fan6_input.dev_attr.attr,
-+
-+ &sensor_dev_attr_fan1_fault.dev_attr.attr,
-+ &sensor_dev_attr_fan2_fault.dev_attr.attr,
-+ &sensor_dev_attr_fan3_fault.dev_attr.attr,
-+ &sensor_dev_attr_fan4_fault.dev_attr.attr,
-+ &sensor_dev_attr_fan5_fault.dev_attr.attr,
-+ &sensor_dev_attr_fan6_fault.dev_attr.attr,
-+
-+ &sensor_dev_attr_fan1_target.dev_attr.attr,
-+ &sensor_dev_attr_fan2_target.dev_attr.attr,
-+ &sensor_dev_attr_fan3_target.dev_attr.attr,
-+ &sensor_dev_attr_fan4_target.dev_attr.attr,
-+ &sensor_dev_attr_fan5_target.dev_attr.attr,
-+ &sensor_dev_attr_fan6_target.dev_attr.attr,
-+
-+ &sensor_dev_attr_fan1_pulses.dev_attr.attr,
-+ &sensor_dev_attr_fan2_pulses.dev_attr.attr,
-+ &sensor_dev_attr_fan3_pulses.dev_attr.attr,
-+ &sensor_dev_attr_fan4_pulses.dev_attr.attr,
-+ &sensor_dev_attr_fan5_pulses.dev_attr.attr,
-+ &sensor_dev_attr_fan6_pulses.dev_attr.attr,
-+
-+ &sensor_dev_attr_pwm1.dev_attr.attr,
-+ &sensor_dev_attr_pwm2.dev_attr.attr,
-+ &sensor_dev_attr_pwm3.dev_attr.attr,
-+ &sensor_dev_attr_pwm4.dev_attr.attr,
-+ &sensor_dev_attr_pwm5.dev_attr.attr,
-+ &sensor_dev_attr_pwm6.dev_attr.attr,
-+
-+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
-+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
-+ &sensor_dev_attr_pwm4_enable.dev_attr.attr,
-+ &sensor_dev_attr_pwm5_enable.dev_attr.attr,
-+ &sensor_dev_attr_pwm6_enable.dev_attr.attr,
-+ NULL
-+};
-+
-+static umode_t max31785_attrs_visible(struct kobject *kobj,
-+ struct attribute *a, int n)
-+{
-+ return a->mode;
-+}
-+
-+static const struct attribute_group max31785_group = {
-+ .attrs = max31785_attrs,
-+ .is_visible = max31785_attrs_visible,
-+};
-+__ATTRIBUTE_GROUPS(max31785);
-+
-+static int max31785_init_client(struct i2c_client *client,
-+ struct max31785_data *data)
-+{
-+ int i, rv;
-+
-+ for (i = 0; i < NR_CHANNEL; i++) {
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_FAN_CONFIG_1_2, 1);
-+ if (rv < 0)
-+ return rv;
-+ data->fan_config[i] = rv;
-+
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_FAN_COMMAND_1, 0);
-+ if (rv < 0)
-+ return rv;
-+ data->fan_command[i] = rv;
-+
-+ rv = max31785_read_fan_data(client, i,
-+ MAX31785_REG_MFR_FAN_CONFIG, 1);
-+ if (rv < 0)
-+ return rv;
-+ data->mfr_fan_config[i] = rv;
-+
-+ if (!((data->fan_config[i]
-+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM)
-+ || is_automatic_control_mode(data, i))) {
-+ data->pwm[i] = 0;
-+ }
-+ }
-+
-+ return rv;
-+}
-+
-+/* Return 0 if detection is successful, -ENODEV otherwise */
-+static int max31785_detect(struct i2c_client *client,
-+ struct i2c_board_info *info)
-+{
-+ struct i2c_adapter *adapter = client->adapter;
-+ int rv;
-+
-+ if (!i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
-+ return -ENODEV;
-+
-+ /* Probe manufacturer / model registers */
-+ rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_ID);
-+ if (rv < 0)
-+ return -ENODEV;
-+ if (rv != MAX31785_MFR_ID)
-+ return -ENODEV;
-+
-+ rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_MODEL);
-+ if (rv < 0)
-+ return -ENODEV;
-+ if (rv != MAX31785_MFR_MODEL)
-+ return -ENODEV;
-+
-+ strlcpy(info->type, "max31785", I2C_NAME_SIZE);
-+
-+ return 0;
-+}
-+
-+static int max31785_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct i2c_adapter *adapter = client->adapter;
-+ struct device *dev = &client->dev;
-+ struct max31785_data *data;
-+ struct device *hwmon_dev;
-+ int err;
-+
-+ if (!i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
-+ return -ENODEV;
-+
-+ data = devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNEL);
-+ if (!data)
-+ return -ENOMEM;
-+
-+ data->client = client;
-+ mutex_init(&data->device_lock);
-+
-+ /*
-+ * Initialize the max31785 chip
-+ */
-+ err = max31785_init_client(client, data);
-+ if (err)
-+ return err;
-+
-+ hwmon_dev = devm_hwmon_device_register_with_groups(dev,
-+ client->name, data, max31785_groups);
-+
-+ return PTR_ERR_OR_ZERO(hwmon_dev);
-+}
-+
-+static const struct i2c_device_id max31785_id[] = {
-+ { "max31785", 0 },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, max31785_id);
-+
-+static struct i2c_driver max31785_driver = {
-+ .class = I2C_CLASS_HWMON,
-+ .probe = max31785_probe,
-+ .driver = {
-+ .name = "max31785",
-+ },
-+ .id_table = max31785_id,
-+ .detect = max31785_detect,
-+ .address_list = normal_i2c,
-+};
-+
-+module_i2c_driver(max31785_driver);
-+
-+MODULE_AUTHOR("Timothy Pearson <tpearson@raptorengineering.com>");
-+MODULE_DESCRIPTION("MAX31785 sensor driver");
-+MODULE_LICENSE("GPL");
---
-1.8.3.1
-
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch
deleted file mode 100644
index 70a11f2..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch
+++ /dev/null
@@ -1,338 +0,0 @@
-From patchwork Fri May 12 19:38:18 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux,dev-4.10,1/3] drivers: fsi: sbefifo: Add in-kernel API
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 761836
-Message-Id: <1494617900-32369-2-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com,
- cbostic@linux.vnet.ibm.com
-Date: Fri, 12 May 2017 14:38:18 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Add exported functions to the SBEFIFO driver to open/write/read/close
-from within the kernel.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/fsi/fsi-sbefifo.c | 161 +++++++++++++++++++++++++++++++++++---------
- include/linux/fsi-sbefifo.h | 30 +++++++++
- 2 files changed, 161 insertions(+), 30 deletions(-)
- create mode 100644 include/linux/fsi-sbefifo.h
-
-diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
-index b49aec2..56e6331 100644
---- a/drivers/fsi/fsi-sbefifo.c
-+++ b/drivers/fsi/fsi-sbefifo.c
-@@ -15,9 +15,12 @@
- #include <linux/errno.h>
- #include <linux/idr.h>
- #include <linux/fsi.h>
-+#include <linux/fsi-sbefifo.h>
- #include <linux/list.h>
- #include <linux/miscdevice.h>
- #include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_platform.h>
- #include <linux/poll.h>
- #include <linux/sched.h>
- #include <linux/slab.h>
-@@ -82,6 +85,7 @@ struct sbefifo_client {
- struct list_head xfrs;
- struct sbefifo *dev;
- struct kref kref;
-+ unsigned long f_flags;
- };
-
- static struct list_head sbefifo_fifos;
-@@ -506,6 +510,7 @@ static int sbefifo_open(struct inode *inode, struct file *file)
- return -ENOMEM;
-
- file->private_data = client;
-+ client->f_flags = file->f_flags;
-
- return 0;
- }
-@@ -530,24 +535,18 @@ static unsigned int sbefifo_poll(struct file *file, poll_table *wait)
- return mask;
- }
-
--static ssize_t sbefifo_read(struct file *file, char __user *buf,
-- size_t len, loff_t *offset)
-+static ssize_t sbefifo_read_common(struct sbefifo_client *client,
-+ char __user *ubuf, char *kbuf, size_t len)
- {
-- struct sbefifo_client *client = file->private_data;
- struct sbefifo *sbefifo = client->dev;
- struct sbefifo_xfr *xfr;
-- ssize_t ret = 0;
- size_t n;
--
-- WARN_ON(*offset);
--
-- if (!access_ok(VERIFY_WRITE, buf, len))
-- return -EFAULT;
-+ ssize_t ret = 0;
-
- if ((len >> 2) << 2 != len)
- return -EINVAL;
-
-- if ((file->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client))
-+ if ((client->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client))
- return -EAGAIN;
-
- sbefifo_get_client(client);
-@@ -566,10 +565,13 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf,
-
- n = min_t(size_t, n, len);
-
-- if (copy_to_user(buf, READ_ONCE(client->rbuf.rpos), n)) {
-- sbefifo_put_client(client);
-- return -EFAULT;
-- }
-+ if (ubuf) {
-+ if (copy_to_user(ubuf, READ_ONCE(client->rbuf.rpos), n)) {
-+ sbefifo_put_client(client);
-+ return -EFAULT;
-+ }
-+ } else
-+ memcpy(kbuf, READ_ONCE(client->rbuf.rpos), n);
-
- if (sbefifo_buf_readnb(&client->rbuf, n)) {
- xfr = sbefifo_client_next_xfr(client);
-@@ -592,20 +594,28 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf,
- return n;
- }
-
--static ssize_t sbefifo_write(struct file *file, const char __user *buf,
-+static ssize_t sbefifo_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
- {
- struct sbefifo_client *client = file->private_data;
-- struct sbefifo *sbefifo = client->dev;
-- struct sbefifo_xfr *xfr;
-- ssize_t ret = 0;
-- size_t n;
-
- WARN_ON(*offset);
-
-- if (!access_ok(VERIFY_READ, buf, len))
-+ if (!access_ok(VERIFY_WRITE, buf, len))
- return -EFAULT;
-
-+ return sbefifo_read_common(client, buf, NULL, len);
-+}
-+
-+static ssize_t sbefifo_write_common(struct sbefifo_client *client,
-+ const char __user *ubuf, const char *kbuf,
-+ size_t len)
-+{
-+ struct sbefifo *sbefifo = client->dev;
-+ struct sbefifo_xfr *xfr;
-+ ssize_t ret = 0;
-+ size_t n;
-+
- if ((len >> 2) << 2 != len)
- return -EINVAL;
-
-@@ -617,7 +627,7 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf,
- spin_lock_irq(&sbefifo->lock);
- xfr = sbefifo_next_xfr(sbefifo);
-
-- if ((file->f_flags & O_NONBLOCK) && xfr && n < len) {
-+ if ((client->f_flags & O_NONBLOCK) && xfr && n < len) {
- spin_unlock_irq(&sbefifo->lock);
- return -EAGAIN;
- }
-@@ -657,18 +667,25 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf,
-
- n = min_t(size_t, n, len);
-
-- if (copy_from_user(READ_ONCE(client->wbuf.wpos), buf, n)) {
-- set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
-- sbefifo_get(sbefifo);
-- if (mod_timer(&sbefifo->poll_timer, jiffies))
-- sbefifo_put(sbefifo);
-- sbefifo_put_client(client);
-- return -EFAULT;
-+ if (ubuf) {
-+ if (copy_from_user(READ_ONCE(client->wbuf.wpos), ubuf,
-+ n)) {
-+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
-+ sbefifo_get(sbefifo);
-+ if (mod_timer(&sbefifo->poll_timer, jiffies))
-+ sbefifo_put(sbefifo);
-+ sbefifo_put_client(client);
-+ return -EFAULT;
-+ }
-+
-+ ubuf += n;
-+ } else {
-+ memcpy(READ_ONCE(client->wbuf.wpos), kbuf, n);
-+ kbuf += n;
- }
-
- sbefifo_buf_wrotenb(&client->wbuf, n);
- len -= n;
-- buf += n;
- ret += n;
-
- /*
-@@ -685,6 +702,19 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf,
- return ret;
- }
-
-+static ssize_t sbefifo_write(struct file *file, const char __user *buf,
-+ size_t len, loff_t *offset)
-+{
-+ struct sbefifo_client *client = file->private_data;
-+
-+ WARN_ON(*offset);
-+
-+ if (!access_ok(VERIFY_READ, buf, len))
-+ return -EFAULT;
-+
-+ return sbefifo_write_common(client, buf, NULL, len);
-+}
-+
- static int sbefifo_release(struct inode *inode, struct file *file)
- {
- struct sbefifo_client *client = file->private_data;
-@@ -704,12 +734,68 @@ static int sbefifo_release(struct inode *inode, struct file *file)
- .release = sbefifo_release,
- };
-
-+struct sbefifo_client *sbefifo_drv_open(struct device *dev,
-+ unsigned long flags)
-+{
-+ struct sbefifo_client *client = NULL;
-+ struct sbefifo *sbefifo;
-+ struct fsi_device *fsi_dev = to_fsi_dev(dev);
-+
-+ list_for_each_entry(sbefifo, &sbefifo_fifos, link) {
-+ if (sbefifo->fsi_dev != fsi_dev)
-+ continue;
-+
-+ client = sbefifo_new_client(sbefifo);
-+ if (client)
-+ client->f_flags = flags;
-+ }
-+
-+ return client;
-+}
-+EXPORT_SYMBOL_GPL(sbefifo_drv_open);
-+
-+int sbefifo_drv_read(struct sbefifo_client *client, char *buf, size_t len)
-+{
-+ return sbefifo_read_common(client, NULL, buf, len);
-+}
-+EXPORT_SYMBOL_GPL(sbefifo_drv_read);
-+
-+int sbefifo_drv_write(struct sbefifo_client *client, const char *buf,
-+ size_t len)
-+{
-+ return sbefifo_write_common(client, NULL, buf, len);
-+}
-+EXPORT_SYMBOL_GPL(sbefifo_drv_write);
-+
-+void sbefifo_drv_release(struct sbefifo_client *client)
-+{
-+ if (!client)
-+ return;
-+
-+ sbefifo_put_client(client);
-+}
-+EXPORT_SYMBOL_GPL(sbefifo_drv_release);
-+
-+static int sbefifo_unregister_child(struct device *dev, void *data)
-+{
-+ struct platform_device *child = to_platform_device(dev);
-+
-+ of_device_unregister(child);
-+ if (dev->of_node)
-+ of_node_clear_flag(dev->of_node, OF_POPULATED);
-+
-+ return 0;
-+}
-+
- static int sbefifo_probe(struct device *dev)
- {
- struct fsi_device *fsi_dev = to_fsi_dev(dev);
- struct sbefifo *sbefifo;
-+ struct device_node *np;
-+ struct platform_device *child;
-+ char child_name[32];
- u32 sts;
-- int ret;
-+ int ret, child_idx = 0;
-
- dev_info(dev, "Found sbefifo device\n");
- sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL);
-@@ -750,6 +836,18 @@ static int sbefifo_probe(struct device *dev)
- init_waitqueue_head(&sbefifo->wait);
- INIT_LIST_HEAD(&sbefifo->xfrs);
-
-+ if (dev->of_node) {
-+ /* create platform devs for dts child nodes (occ, etc) */
-+ for_each_child_of_node(dev->of_node, np) {
-+ snprintf(child_name, sizeof(child_name), "%s-dev%d",
-+ sbefifo->name, child_idx++);
-+ child = of_platform_device_create(np, child_name, dev);
-+ if (!child)
-+ dev_warn(&sbefifo->fsi_dev->dev,
-+ "failed to create child node dev\n");
-+ }
-+ }
-+
- /* This bit of silicon doesn't offer any interrupts... */
- setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer,
- (unsigned long)sbefifo);
-@@ -767,6 +865,9 @@ static int sbefifo_remove(struct device *dev)
- list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) {
- if (sbefifo->fsi_dev != fsi_dev)
- continue;
-+
-+ device_for_each_child(dev, NULL, sbefifo_unregister_child);
-+
- misc_deregister(&sbefifo->mdev);
- list_del(&sbefifo->link);
- ida_simple_remove(&sbefifo_ida, sbefifo->idx);
-diff --git a/include/linux/fsi-sbefifo.h b/include/linux/fsi-sbefifo.h
-new file mode 100644
-index 0000000..1b46c63
---- /dev/null
-+++ b/include/linux/fsi-sbefifo.h
-@@ -0,0 +1,30 @@
-+/*
-+ * SBEFIFO FSI Client device driver
-+ *
-+ * Copyright (C) IBM Corporation 2017
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __FSI_SBEFIFO_H__
-+#define __FSI_SBEFIFO_H__
-+
-+struct device;
-+struct sbefifo_client;
-+
-+extern struct sbefifo_client *sbefifo_drv_open(struct device *dev,
-+ unsigned long flags);
-+extern int sbefifo_drv_read(struct sbefifo_client *client, char *buf,
-+ size_t len);
-+extern int sbefifo_drv_write(struct sbefifo_client *client, const char *buf,
-+ size_t len);
-+extern void sbefifo_drv_release(struct sbefifo_client *client);
-+
-+#endif /* __FSI_SBEFIFO_H__ */
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch
deleted file mode 100644
index 5c53dad..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch
+++ /dev/null
@@ -1,694 +0,0 @@
-From patchwork Fri May 12 19:38:19 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux,dev-4.10,2/3] drivers: fsi: sbefifo: Add OCC driver
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 761838
-Message-Id: <1494617900-32369-3-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com,
- cbostic@linux.vnet.ibm.com
-Date: Fri, 12 May 2017 14:38:19 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-This driver provides an atomic communications channel between the OCC on
-the POWER9 processor and a service processor (a BMC). The driver is
-dependent on the FSI SBEIFO driver to get hardware access to the OCC
-SRAM.
-
-The format of the communication is a command followed by a response.
-Since the command and response must be performed atomically, the driver
-will perform this operations asynchronously. In this way, a write
-operation starts the command, and a read will gather the response data
-once it is complete.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/fsi/Kconfig | 9 +
- drivers/fsi/Makefile | 1 +
- drivers/fsi/occ.c | 625 +++++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 635 insertions(+)
- create mode 100644 drivers/fsi/occ.c
-
-diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
-index 39527fa..f3d8593 100644
---- a/drivers/fsi/Kconfig
-+++ b/drivers/fsi/Kconfig
-@@ -36,6 +36,15 @@ config FSI_SBEFIFO
- ---help---
- This option enables an FSI based SBEFIFO device driver.
-
-+if FSI_SBEFIFO
-+
-+config OCCFIFO
-+ tristate "OCC SBEFIFO client device driver"
-+ ---help---
-+ This option enables an SBEFIFO based OCC device driver.
-+
-+endif
-+
- endif
-
- endmenu
-diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
-index 851182e..336d9d5 100644
---- a/drivers/fsi/Makefile
-+++ b/drivers/fsi/Makefile
-@@ -4,3 +4,4 @@ obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
- obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
- obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
- obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o
-+obj-$(CONFIG_OCCFIFO) += occ.o
-diff --git a/drivers/fsi/occ.c b/drivers/fsi/occ.c
-new file mode 100644
-index 0000000..74272c8
---- /dev/null
-+++ b/drivers/fsi/occ.c
-@@ -0,0 +1,625 @@
-+/*
-+ * Copyright 2017 IBM Corp.
-+ *
-+ * 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 <asm/unaligned.h>
-+#include <linux/device.h>
-+#include <linux/err.h>
-+#include <linux/fsi-sbefifo.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+#include <linux/wait.h>
-+#include <linux/workqueue.h>
-+
-+#define OCC_SRAM_BYTES 4096
-+#define OCC_CMD_DATA_BYTES 4090
-+#define OCC_RESP_DATA_BYTES 4089
-+
-+struct occ {
-+ struct device *sbefifo;
-+ char name[32];
-+ int idx;
-+ struct miscdevice mdev;
-+ struct list_head xfrs;
-+ spinlock_t list_lock;
-+ spinlock_t occ_lock;
-+ struct work_struct work;
-+};
-+
-+#define to_occ(x) container_of((x), struct occ, mdev)
-+
-+struct occ_command {
-+ u8 seq_no;
-+ u8 cmd_type;
-+ u16 data_length;
-+ u8 data[OCC_CMD_DATA_BYTES];
-+ u16 checksum;
-+};
-+
-+struct occ_response {
-+ u8 seq_no;
-+ u8 cmd_type;
-+ u8 return_status;
-+ u16 data_length;
-+ u8 data[OCC_RESP_DATA_BYTES];
-+ u16 checksum;
-+};
-+
-+struct occ_xfr;
-+
-+enum {
-+ CLIENT_NONBLOCKING,
-+};
-+
-+struct occ_client {
-+ struct occ *occ;
-+ struct occ_xfr *xfr;
-+ spinlock_t lock;
-+ wait_queue_head_t wait;
-+ size_t read_offset;
-+ unsigned long flags;
-+};
-+
-+enum {
-+ XFR_IN_PROGRESS,
-+ XFR_COMPLETE,
-+ XFR_CANCELED,
-+ XFR_WAITING,
-+};
-+
-+struct occ_xfr {
-+ struct list_head link;
-+ struct occ_client *client;
-+ int rc;
-+ u8 buf[OCC_SRAM_BYTES];
-+ size_t cmd_data_length;
-+ size_t resp_data_length;
-+ unsigned long flags;
-+};
-+
-+static struct workqueue_struct *occ_wq;
-+
-+static DEFINE_IDA(occ_ida);
-+
-+static void occ_enqueue_xfr(struct occ_xfr *xfr)
-+{
-+ int empty;
-+ struct occ *occ = xfr->client->occ;
-+
-+ spin_lock_irq(&occ->list_lock);
-+ empty = list_empty(&occ->xfrs);
-+ list_add_tail(&xfr->link, &occ->xfrs);
-+ spin_unlock(&occ->list_lock);
-+
-+ if (empty)
-+ queue_work(occ_wq, &occ->work);
-+}
-+
-+static int occ_open(struct inode *inode, struct file *file)
-+{
-+ struct occ_client *client;
-+ struct miscdevice *mdev = file->private_data;
-+ struct occ *occ = to_occ(mdev);
-+
-+ client = kzalloc(sizeof(*client), GFP_KERNEL);
-+ if (!client)
-+ return -ENOMEM;
-+
-+ client->occ = occ;
-+ spin_lock_init(&client->lock);
-+ init_waitqueue_head(&client->wait);
-+
-+ if (file->f_flags & O_NONBLOCK)
-+ set_bit(CLIENT_NONBLOCKING, &client->flags);
-+
-+ file->private_data = client;
-+
-+ return 0;
-+}
-+
-+static ssize_t occ_read(struct file *file, char __user *buf, size_t len,
-+ loff_t *offset)
-+{
-+ int rc;
-+ size_t bytes;
-+ struct occ_xfr *xfr;
-+ struct occ_client *client = file->private_data;
-+
-+ if (!access_ok(VERIFY_WRITE, buf, len))
-+ return -EFAULT;
-+
-+ if (len > OCC_SRAM_BYTES)
-+ return -EINVAL;
-+
-+ spin_lock_irq(&client->lock);
-+ if (!client->xfr) {
-+ /* we just finished reading all data, return 0 */
-+ if (client->read_offset) {
-+ rc = 0;
-+ client->read_offset = 0;
-+ } else
-+ rc = -ENOMSG;
-+
-+ goto done;
-+ }
-+
-+ xfr = client->xfr;
-+
-+ if (!test_bit(XFR_COMPLETE, &xfr->flags)) {
-+ if (client->flags & CLIENT_NONBLOCKING) {
-+ rc = -ERESTARTSYS;
-+ goto done;
-+ }
-+
-+ set_bit(XFR_WAITING, &xfr->flags);
-+ spin_unlock(&client->lock);
-+
-+ rc = wait_event_interruptible(client->wait,
-+ test_bit(XFR_COMPLETE, &xfr->flags) ||
-+ test_bit(XFR_CANCELED, &xfr->flags));
-+
-+ spin_lock_irq(&client->lock);
-+ if (test_bit(XFR_CANCELED, &xfr->flags)) {
-+ kfree(xfr);
-+ spin_unlock(&client->lock);
-+ kfree(client);
-+ return -EBADFD;
-+ }
-+
-+ clear_bit(XFR_WAITING, &xfr->flags);
-+ if (!test_bit(XFR_COMPLETE, &xfr->flags)) {
-+ rc = -EINTR;
-+ goto done;
-+ }
-+ }
-+
-+ if (xfr->rc) {
-+ rc = xfr->rc;
-+ goto done;
-+ }
-+
-+ bytes = min(len, xfr->resp_data_length - client->read_offset);
-+ if (copy_to_user(buf, &xfr->buf[client->read_offset], bytes)) {
-+ rc = -EFAULT;
-+ goto done;
-+ }
-+
-+ client->read_offset += bytes;
-+
-+ /* xfr done */
-+ if (client->read_offset == xfr->resp_data_length) {
-+ kfree(xfr);
-+ client->xfr = NULL;
-+ }
-+
-+ rc = bytes;
-+
-+done:
-+ spin_unlock(&client->lock);
-+ return rc;
-+}
-+
-+static ssize_t occ_write(struct file *file, const char __user *buf,
-+ size_t len, loff_t *offset)
-+{
-+ int rc;
-+ struct occ_xfr *xfr;
-+ struct occ_client *client = file->private_data;
-+
-+ if (!access_ok(VERIFY_READ, buf, len))
-+ return -EFAULT;
-+
-+ if (len > OCC_SRAM_BYTES)
-+ return -EINVAL;
-+
-+ spin_lock_irq(&client->lock);
-+ if (client->xfr) {
-+ rc = -EDEADLK;
-+ goto done;
-+ }
-+
-+ xfr = kzalloc(sizeof(*xfr), GFP_KERNEL);
-+ if (!xfr) {
-+ rc = -ENOMEM;
-+ goto done;
-+ }
-+
-+ if (copy_from_user(xfr->buf, buf, len)) {
-+ kfree(xfr);
-+ rc = -EFAULT;
-+ goto done;
-+ }
-+
-+ xfr->client = client;
-+ xfr->cmd_data_length = len;
-+ client->xfr = xfr;
-+ client->read_offset = 0;
-+
-+ occ_enqueue_xfr(xfr);
-+
-+ rc = len;
-+
-+done:
-+ spin_unlock(&client->lock);
-+ return rc;
-+}
-+
-+static int occ_release(struct inode *inode, struct file *file)
-+{
-+ struct occ_xfr *xfr;
-+ struct occ_client *client = file->private_data;
-+ struct occ *occ = client->occ;
-+
-+ spin_lock_irq(&client->lock);
-+ xfr = client->xfr;
-+ if (!xfr) {
-+ spin_unlock(&client->lock);
-+ kfree(client);
-+ return 0;
-+ }
-+
-+ spin_lock_irq(&occ->list_lock);
-+ set_bit(XFR_CANCELED, &xfr->flags);
-+ if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) {
-+ /* already deleted from list if complete */
-+ if (!test_bit(XFR_COMPLETE, &xfr->flags))
-+ list_del(&xfr->link);
-+
-+ spin_unlock(&occ->list_lock);
-+
-+ if (test_bit(XFR_WAITING, &xfr->flags)) {
-+ /* blocking read; let reader clean up */
-+ wake_up_interruptible(&client->wait);
-+ spin_unlock(&client->lock);
-+ return 0;
-+ }
-+
-+ kfree(xfr);
-+ spin_unlock(&client->lock);
-+ kfree(client);
-+ return 0;
-+ }
-+
-+ /* operation is in progress; let worker clean up*/
-+ spin_unlock(&occ->list_lock);
-+ spin_unlock(&client->lock);
-+ return 0;
-+}
-+
-+static const struct file_operations occ_fops = {
-+ .owner = THIS_MODULE,
-+ .open = occ_open,
-+ .read = occ_read,
-+ .write = occ_write,
-+ .release = occ_release,
-+};
-+
-+static int occ_getscom(struct device *sbefifo, u32 address, u8 *data)
-+{
-+ int rc;
-+ u32 buf[4];
-+ struct sbefifo_client *client;
-+ const size_t len = sizeof(buf);
-+
-+ buf[0] = cpu_to_be32(0x4);
-+ buf[1] = cpu_to_be32(0xa201);
-+ buf[2] = 0;
-+ buf[3] = cpu_to_be32(address);
-+
-+ client = sbefifo_drv_open(sbefifo, 0);
-+ if (!client)
-+ return -ENODEV;
-+
-+ rc = sbefifo_drv_write(client, (const char *)buf, len);
-+ if (rc < 0)
-+ goto done;
-+ else if (rc != len) {
-+ rc = -EMSGSIZE;
-+ goto done;
-+ }
-+
-+ rc = sbefifo_drv_read(client, (char *)buf, len);
-+ if (rc < 0)
-+ goto done;
-+ else if (rc != len) {
-+ rc = -EMSGSIZE;
-+ goto done;
-+ }
-+
-+ /* check for good response */
-+ if ((be32_to_cpu(buf[2]) >> 16) != 0xC0DE) {
-+ rc = -EFAULT;
-+ goto done;
-+ }
-+
-+ rc = 0;
-+
-+ memcpy(data, buf, sizeof(u64));
-+
-+done:
-+ sbefifo_drv_release(client);
-+ return rc;
-+}
-+
-+static int occ_putscom(struct device *sbefifo, u32 address, u8 *data)
-+{
-+ int rc;
-+ u32 buf[6];
-+ struct sbefifo_client *client;
-+ const size_t len = sizeof(buf);
-+
-+ buf[0] = cpu_to_be32(0x6);
-+ buf[1] = cpu_to_be32(0xa202);
-+ buf[2] = 0;
-+ buf[3] = cpu_to_be32(address);
-+ memcpy(&buf[4], data, sizeof(u64));
-+
-+ client = sbefifo_drv_open(sbefifo, 0);
-+ if (!client)
-+ return -ENODEV;
-+
-+ rc = sbefifo_drv_write(client, (const char *)buf, len);
-+ if (rc < 0)
-+ goto done;
-+ else if (rc != len) {
-+ rc = -EMSGSIZE;
-+ goto done;
-+ }
-+
-+ rc = 0;
-+
-+ /* ignore response */
-+ sbefifo_drv_read(client, (char *)buf, len);
-+
-+done:
-+ sbefifo_drv_release(client);
-+ return rc;
-+}
-+
-+static int occ_putscom_u32(struct device *sbefifo, u32 address, u32 data0,
-+ u32 data1)
-+{
-+ u8 buf[8];
-+ u32 raw_data0 = cpu_to_be32(data0), raw_data1 = cpu_to_be32(data1);
-+
-+ memcpy(buf, &raw_data0, 4);
-+ memcpy(buf + 4, &raw_data1, 4);
-+
-+ return occ_putscom(sbefifo, address, buf);
-+}
-+
-+static void occ_worker(struct work_struct *work)
-+{
-+ int i, empty, canceled, waiting, rc;
-+ u16 resp_data_length;
-+ struct occ *occ = container_of(work, struct occ, work);
-+ struct device *sbefifo = occ->sbefifo;
-+ struct occ_client *client;
-+ struct occ_xfr *xfr;
-+ struct occ_response *resp;
-+
-+again:
-+ spin_lock_irq(&occ->list_lock);
-+ xfr = list_first_entry(&occ->xfrs, struct occ_xfr, link);
-+ if (!xfr) {
-+ spin_unlock(&occ->list_lock);
-+ return;
-+ }
-+
-+ set_bit(XFR_IN_PROGRESS, &xfr->flags);
-+ spin_unlock(&occ->list_lock);
-+
-+ resp = (struct occ_response *)xfr->buf;
-+
-+ spin_lock_irq(&occ->occ_lock);
-+
-+ /* set address reg to occ sram command buffer */
-+ rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBE000, 0);
-+ if (rc)
-+ goto done;
-+
-+ /* write cmd data */
-+ for (i = 0; i < xfr->cmd_data_length; i += 8) {
-+ rc = occ_putscom(sbefifo, 0x6D055, &xfr->buf[i]);
-+ if (rc)
-+ goto done;
-+ }
-+
-+ /* trigger attention */
-+ rc = occ_putscom_u32(sbefifo, 0x6D035, 0x20010000, 0);
-+ if (rc)
-+ goto done;
-+
-+ /* set address reg to occ sram response buffer */
-+ rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBF000, 0);
-+ if (rc)
-+ goto done;
-+
-+ rc = occ_getscom(sbefifo, 0x6D055, xfr->buf);
-+ if (rc)
-+ goto done;
-+
-+ xfr->resp_data_length += 8;
-+
-+ resp_data_length = be16_to_cpu(get_unaligned(&resp->data_length));
-+ if (resp_data_length > OCC_RESP_DATA_BYTES) {
-+ rc = -EFAULT;
-+ goto done;
-+ }
-+
-+ /* already read 3 bytes of resp data, but also need 2 bytes chksum */
-+ for (i = 8; i < resp_data_length + 7; i += 8) {
-+ rc = occ_getscom(sbefifo, 0x6D055, &xfr->buf[i]);
-+ if (rc)
-+ goto done;
-+
-+ xfr->resp_data_length += 8;
-+ }
-+
-+ /* no errors, got all data */
-+ xfr->resp_data_length = resp_data_length + 7;
-+
-+done:
-+ spin_unlock(&occ->occ_lock);
-+
-+ xfr->rc = rc;
-+ client = xfr->client;
-+
-+ /* lock client to prevent race with read() */
-+ spin_lock_irq(&client->lock);
-+ set_bit(XFR_COMPLETE, &xfr->flags);
-+ waiting = test_bit(XFR_WAITING, &xfr->flags);
-+ spin_unlock(&client->lock);
-+
-+ spin_lock_irq(&occ->list_lock);
-+ clear_bit(XFR_IN_PROGRESS, &xfr->flags);
-+ list_del(&xfr->link);
-+ empty = list_empty(&occ->xfrs);
-+ canceled = test_bit(XFR_CANCELED, &xfr->flags);
-+ spin_unlock(&occ->list_lock);
-+
-+ if (waiting)
-+ wake_up_interruptible(&client->wait);
-+ else if (canceled) {
-+ kfree(xfr);
-+ kfree(xfr->client);
-+ }
-+
-+ if (!empty)
-+ goto again;
-+}
-+
-+static int occ_probe(struct platform_device *pdev)
-+{
-+ int rc;
-+ u32 reg;
-+ struct occ *occ;
-+ struct device *dev = &pdev->dev;
-+
-+ dev_info(dev, "Found occ device\n");
-+ occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL);
-+ if (!occ)
-+ return -ENOMEM;
-+
-+ occ->sbefifo = dev->parent;
-+ INIT_LIST_HEAD(&occ->xfrs);
-+ spin_lock_init(&occ->list_lock);
-+ spin_lock_init(&occ->occ_lock);
-+ INIT_WORK(&occ->work, occ_worker);
-+
-+ if (dev->of_node) {
-+ rc = of_property_read_u32(dev->of_node, "reg", ®);
-+ if (!rc) {
-+ /* make sure we don't have a duplicate from dts */
-+ occ->idx = ida_simple_get(&occ_ida, reg, reg + 1,
-+ GFP_KERNEL);
-+ if (occ->idx < 0)
-+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX,
-+ GFP_KERNEL);
-+ } else
-+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX,
-+ GFP_KERNEL);
-+ } else
-+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, GFP_KERNEL);
-+
-+ snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx);
-+ occ->mdev.fops = &occ_fops;
-+ occ->mdev.minor = MISC_DYNAMIC_MINOR;
-+ occ->mdev.name = occ->name;
-+ occ->mdev.parent = dev;
-+
-+ rc = misc_register(&occ->mdev);
-+ if (rc) {
-+ dev_err(dev, "failed to register miscdevice\n");
-+ return rc;
-+ }
-+
-+ platform_set_drvdata(pdev, occ);
-+
-+ return 0;
-+}
-+
-+static int occ_remove(struct platform_device *pdev)
-+{
-+ struct occ_xfr *xfr, *tmp;
-+ struct occ *occ = platform_get_drvdata(pdev);
-+ struct occ_client *client;
-+
-+ misc_deregister(&occ->mdev);
-+
-+ spin_lock_irq(&occ->list_lock);
-+ list_for_each_entry_safe(xfr, tmp, &occ->xfrs, link) {
-+ client = xfr->client;
-+ set_bit(XFR_CANCELED, &xfr->flags);
-+
-+ if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) {
-+ list_del(&xfr->link);
-+
-+ spin_lock_irq(&client->lock);
-+ if (test_bit(XFR_WAITING, &xfr->flags)) {
-+ wake_up_interruptible(&client->wait);
-+ spin_unlock(&client->lock);
-+ } else {
-+ kfree(xfr);
-+ spin_unlock(&client->lock);
-+ kfree(client);
-+ }
-+ }
-+ }
-+ spin_unlock(&occ->list_lock);
-+
-+ flush_work(&occ->work);
-+
-+ ida_simple_remove(&occ_ida, occ->idx);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id occ_match[] = {
-+ { .compatible = "ibm,p9-occ" },
-+ { },
-+};
-+
-+static struct platform_driver occ_driver = {
-+ .driver = {
-+ .name = "occ",
-+ .of_match_table = occ_match,
-+ },
-+ .probe = occ_probe,
-+ .remove = occ_remove,
-+};
-+
-+static int occ_init(void)
-+{
-+ occ_wq = create_singlethread_workqueue("occ");
-+ if (!occ_wq)
-+ return -ENOMEM;
-+
-+ return platform_driver_register(&occ_driver);
-+}
-+
-+static void occ_exit(void)
-+{
-+ destroy_workqueue(occ_wq);
-+
-+ platform_driver_unregister(&occ_driver);
-+}
-+
-+module_init(occ_init);
-+module_exit(occ_exit);
-+
-+MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>");
-+MODULE_DESCRIPTION("BMC P9 OCC driver");
-+MODULE_LICENSE("GPL");
-+
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch
deleted file mode 100644
index b29e0e9..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch
+++ /dev/null
@@ -1,899 +0,0 @@
-From patchwork Thu May 11 02:52:53 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux,dev-4.10] drivers: fsi: Add FSI SBEFIFO driver
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760920
-Message-Id: <1494471173-6077-1-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com
-Date: Wed, 10 May 2017 21:52:53 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-IBM POWER9 processors contain some embedded hardware and software bits
-collectively referred to as the self boot engine (SBE). One role of
-the SBE is to act as a proxy that provides access to the registers of
-the POWER chip from other (embedded) systems.
-
-The POWER9 chip contains a hardware frontend for communicating with
-the SBE from remote systems called the SBEFIFO. The SBEFIFO logic
-is contained within an FSI CFAM (see Documentation/fsi) and as such
-the driver implements an FSI bus device.
-
-The SBE expects to communicate using a defined wire protocol; however,
-the driver knows nothing of the protocol and only provides raw access
-to the fifo device to userspace applications wishing to communicate with
-the SBE using the wire protocol.
-
-The SBEFIFO consists of two hardware fifos. The upstream fifo is used
-by the driver to transfer data to the SBE on the POWER chip, from the
-system hosting the driver. The downstream fifo is used by the driver to
-transfer data from the SBE on the power chip to the system hosting the
-driver.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
-Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
----
- drivers/fsi/Kconfig | 5 +
- drivers/fsi/Makefile | 1 +
- drivers/fsi/fsi-sbefifo.c | 824 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 830 insertions(+)
- create mode 100644 drivers/fsi/fsi-sbefifo.c
-
-diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
-index fc031ac..39527fa 100644
---- a/drivers/fsi/Kconfig
-+++ b/drivers/fsi/Kconfig
-@@ -31,6 +31,11 @@ config FSI_SCOM
- ---help---
- This option enables an FSI based SCOM device driver.
-
-+config FSI_SBEFIFO
-+ tristate "SBEFIFO FSI client device driver"
-+ ---help---
-+ This option enables an FSI based SBEFIFO device driver.
-+
- endif
-
- endmenu
-diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
-index 65eb99d..851182e 100644
---- a/drivers/fsi/Makefile
-+++ b/drivers/fsi/Makefile
-@@ -3,3 +3,4 @@ obj-$(CONFIG_FSI) += fsi-core.o
- obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
- obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
- obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
-+obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o
-diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
-new file mode 100644
-index 0000000..b49aec2
---- /dev/null
-+++ b/drivers/fsi/fsi-sbefifo.c
-@@ -0,0 +1,824 @@
-+/*
-+ * Copyright (C) IBM Corporation 2017
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/errno.h>
-+#include <linux/idr.h>
-+#include <linux/fsi.h>
-+#include <linux/list.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/poll.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/timer.h>
-+#include <linux/uaccess.h>
-+
-+/*
-+ * The SBEFIFO is a pipe-like FSI device for communicating with
-+ * the self boot engine on POWER processors.
-+ */
-+
-+#define DEVICE_NAME "sbefifo"
-+#define FSI_ENGID_SBE 0x22
-+#define SBEFIFO_BUF_CNT 32
-+
-+#define SBEFIFO_UP 0x00 /* Up register offset */
-+#define SBEFIFO_DWN 0x40 /* Down register offset */
-+
-+#define SBEFIFO_STS 0x04
-+#define SBEFIFO_EMPTY BIT(20)
-+#define SBEFIFO_EOT_RAISE 0x08
-+#define SBEFIFO_EOT_MAGIC 0xffffffff
-+#define SBEFIFO_EOT_ACK 0x14
-+
-+struct sbefifo {
-+ struct timer_list poll_timer;
-+ struct fsi_device *fsi_dev;
-+ struct miscdevice mdev;
-+ wait_queue_head_t wait;
-+ struct list_head link;
-+ struct list_head xfrs;
-+ struct kref kref;
-+ spinlock_t lock;
-+ char name[32];
-+ int idx;
-+ int rc;
-+};
-+
-+struct sbefifo_buf {
-+ u32 buf[SBEFIFO_BUF_CNT];
-+ unsigned long flags;
-+#define SBEFIFO_BUF_FULL 1
-+ u32 *rpos;
-+ u32 *wpos;
-+};
-+
-+struct sbefifo_xfr {
-+ struct sbefifo_buf *rbuf;
-+ struct sbefifo_buf *wbuf;
-+ struct list_head client;
-+ struct list_head xfrs;
-+ unsigned long flags;
-+#define SBEFIFO_XFR_WRITE_DONE 1
-+#define SBEFIFO_XFR_RESP_PENDING 2
-+#define SBEFIFO_XFR_COMPLETE 3
-+#define SBEFIFO_XFR_CANCEL 4
-+};
-+
-+struct sbefifo_client {
-+ struct sbefifo_buf rbuf;
-+ struct sbefifo_buf wbuf;
-+ struct list_head xfrs;
-+ struct sbefifo *dev;
-+ struct kref kref;
-+};
-+
-+static struct list_head sbefifo_fifos;
-+
-+static DEFINE_IDA(sbefifo_ida);
-+
-+static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word)
-+{
-+ int rc;
-+ u32 raw_word;
-+
-+ rc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word,
-+ sizeof(raw_word));
-+ if (rc)
-+ return rc;
-+
-+ *word = be32_to_cpu(raw_word);
-+ return 0;
-+}
-+
-+static int sbefifo_outw(struct sbefifo *sbefifo, int reg, u32 word)
-+{
-+ u32 raw_word = cpu_to_be32(word);
-+
-+ return fsi_device_write(sbefifo->fsi_dev, reg, &raw_word,
-+ sizeof(raw_word));
-+}
-+
-+static int sbefifo_readw(struct sbefifo *sbefifo, u32 *word)
-+{
-+ return fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DWN, word,
-+ sizeof(*word));
-+}
-+
-+static int sbefifo_writew(struct sbefifo *sbefifo, u32 word)
-+{
-+ return fsi_device_write(sbefifo->fsi_dev, SBEFIFO_UP, &word,
-+ sizeof(word));
-+}
-+
-+static int sbefifo_ack_eot(struct sbefifo *sbefifo)
-+{
-+ u32 discard;
-+ int ret;
-+
-+ /* Discard the EOT word. */
-+ ret = sbefifo_readw(sbefifo, &discard);
-+ if (ret)
-+ return ret;
-+
-+ return sbefifo_outw(sbefifo, SBEFIFO_DWN | SBEFIFO_EOT_ACK,
-+ SBEFIFO_EOT_MAGIC);
-+}
-+
-+static size_t sbefifo_dev_nwreadable(u32 sts)
-+{
-+ static const u32 FIFO_NTRY_CNT_MSK = 0x000f0000;
-+ static const unsigned int FIFO_NTRY_CNT_SHIFT = 16;
-+
-+ return (sts & FIFO_NTRY_CNT_MSK) >> FIFO_NTRY_CNT_SHIFT;
-+}
-+
-+static size_t sbefifo_dev_nwwriteable(u32 sts)
-+{
-+ static const size_t FIFO_DEPTH = 8;
-+
-+ return FIFO_DEPTH - sbefifo_dev_nwreadable(sts);
-+}
-+
-+static void sbefifo_buf_init(struct sbefifo_buf *buf)
-+{
-+ WRITE_ONCE(buf->rpos, buf->buf);
-+ WRITE_ONCE(buf->wpos, buf->buf);
-+}
-+
-+static size_t sbefifo_buf_nbreadable(struct sbefifo_buf *buf)
-+{
-+ size_t n;
-+ u32 *rpos = READ_ONCE(buf->rpos);
-+ u32 *wpos = READ_ONCE(buf->wpos);
-+
-+ if (test_bit(SBEFIFO_BUF_FULL, &buf->flags))
-+ n = SBEFIFO_BUF_CNT;
-+ else if (rpos <= wpos)
-+ n = wpos - rpos;
-+ else
-+ n = (buf->buf + SBEFIFO_BUF_CNT) - rpos;
-+
-+ return n << 2;
-+}
-+
-+static size_t sbefifo_buf_nbwriteable(struct sbefifo_buf *buf)
-+{
-+ size_t n;
-+ u32 *rpos = READ_ONCE(buf->rpos);
-+ u32 *wpos = READ_ONCE(buf->wpos);
-+
-+ if (test_bit(SBEFIFO_BUF_FULL, &buf->flags))
-+ n = 0;
-+ else if (wpos < rpos)
-+ n = rpos - wpos;
-+ else
-+ n = (buf->buf + SBEFIFO_BUF_CNT) - wpos;
-+
-+ return n << 2;
-+}
-+
-+/*
-+ * Update pointers and flags after doing a buffer read. Return true if the
-+ * buffer is now empty;
-+ */
-+static bool sbefifo_buf_readnb(struct sbefifo_buf *buf, size_t n)
-+{
-+ u32 *rpos = READ_ONCE(buf->rpos);
-+ u32 *wpos = READ_ONCE(buf->wpos);
-+
-+ if (n)
-+ clear_bit(SBEFIFO_BUF_FULL, &buf->flags);
-+
-+ rpos += (n >> 2);
-+ if (rpos == buf->buf + SBEFIFO_BUF_CNT)
-+ rpos = buf->buf;
-+
-+ WRITE_ONCE(buf->rpos, rpos);
-+ return rpos == wpos;
-+}
-+
-+/*
-+ * Update pointers and flags after doing a buffer write. Return true if the
-+ * buffer is now full.
-+ */
-+static bool sbefifo_buf_wrotenb(struct sbefifo_buf *buf, size_t n)
-+{
-+ u32 *rpos = READ_ONCE(buf->rpos);
-+ u32 *wpos = READ_ONCE(buf->wpos);
-+
-+ wpos += (n >> 2);
-+ if (wpos == buf->buf + SBEFIFO_BUF_CNT)
-+ wpos = buf->buf;
-+ if (wpos == rpos)
-+ set_bit(SBEFIFO_BUF_FULL, &buf->flags);
-+
-+ WRITE_ONCE(buf->wpos, wpos);
-+ return rpos == wpos;
-+}
-+
-+static void sbefifo_free(struct kref *kref)
-+{
-+ struct sbefifo *sbefifo;
-+
-+ sbefifo = container_of(kref, struct sbefifo, kref);
-+ kfree(sbefifo);
-+}
-+
-+static void sbefifo_get(struct sbefifo *sbefifo)
-+{
-+ kref_get(&sbefifo->kref);
-+}
-+
-+static void sbefifo_put(struct sbefifo *sbefifo)
-+{
-+ kref_put(&sbefifo->kref, sbefifo_free);
-+}
-+
-+static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client)
-+{
-+ struct sbefifo *sbefifo = client->dev;
-+ struct sbefifo_xfr *xfr;
-+
-+ xfr = kzalloc(sizeof(*xfr), GFP_KERNEL);
-+ if (!xfr)
-+ return NULL;
-+
-+ xfr->rbuf = &client->rbuf;
-+ xfr->wbuf = &client->wbuf;
-+ list_add_tail(&xfr->xfrs, &sbefifo->xfrs);
-+ list_add_tail(&xfr->client, &client->xfrs);
-+
-+ return xfr;
-+}
-+
-+static struct sbefifo_xfr *sbefifo_client_next_xfr(
-+ struct sbefifo_client *client)
-+{
-+ if (list_empty(&client->xfrs))
-+ return NULL;
-+
-+ return container_of(client->xfrs.next, struct sbefifo_xfr,
-+ client);
-+}
-+
-+static bool sbefifo_xfr_rsp_pending(struct sbefifo_client *client)
-+{
-+ struct sbefifo_xfr *xfr;
-+
-+ xfr = sbefifo_client_next_xfr(client);
-+ if (xfr && test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags))
-+ return true;
-+
-+ return false;
-+}
-+
-+static struct sbefifo_client *sbefifo_new_client(struct sbefifo *sbefifo)
-+{
-+ struct sbefifo_client *client;
-+
-+ client = kzalloc(sizeof(*client), GFP_KERNEL);
-+ if (!client)
-+ return NULL;
-+
-+ kref_init(&client->kref);
-+ client->dev = sbefifo;
-+ sbefifo_buf_init(&client->rbuf);
-+ sbefifo_buf_init(&client->wbuf);
-+ INIT_LIST_HEAD(&client->xfrs);
-+
-+ sbefifo_get(sbefifo);
-+
-+ return client;
-+}
-+
-+static void sbefifo_client_release(struct kref *kref)
-+{
-+ struct sbefifo_client *client;
-+ struct sbefifo_xfr *xfr;
-+
-+ client = container_of(kref, struct sbefifo_client, kref);
-+ list_for_each_entry(xfr, &client->xfrs, client) {
-+ /*
-+ * The client left with pending or running xfrs.
-+ * Cancel them.
-+ */
-+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
-+ sbefifo_get(client->dev);
-+ if (mod_timer(&client->dev->poll_timer, jiffies))
-+ sbefifo_put(client->dev);
-+ }
-+
-+ sbefifo_put(client->dev);
-+ kfree(client);
-+}
-+
-+static void sbefifo_get_client(struct sbefifo_client *client)
-+{
-+ kref_get(&client->kref);
-+}
-+
-+static void sbefifo_put_client(struct sbefifo_client *client)
-+{
-+ kref_put(&client->kref, sbefifo_client_release);
-+}
-+
-+static struct sbefifo_xfr *sbefifo_next_xfr(struct sbefifo *sbefifo)
-+{
-+ struct sbefifo_xfr *xfr, *tmp;
-+
-+ list_for_each_entry_safe(xfr, tmp, &sbefifo->xfrs, xfrs) {
-+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags))) {
-+ /* Discard cancelled transfers. */
-+ list_del(&xfr->xfrs);
-+ kfree(xfr);
-+ continue;
-+ }
-+ return xfr;
-+ }
-+
-+ return NULL;
-+}
-+
-+static void sbefifo_poll_timer(unsigned long data)
-+{
-+ static const unsigned long EOT_MASK = 0x000000ff;
-+ struct sbefifo *sbefifo = (void *)data;
-+ struct sbefifo_buf *rbuf, *wbuf;
-+ struct sbefifo_xfr *xfr = NULL;
-+ struct sbefifo_buf drain;
-+ size_t devn, bufn;
-+ int eot = 0;
-+ int ret = 0;
-+ u32 sts;
-+ int i;
-+
-+ spin_lock(&sbefifo->lock);
-+ xfr = list_first_entry_or_null(&sbefifo->xfrs, struct sbefifo_xfr,
-+ xfrs);
-+ if (!xfr)
-+ goto out_unlock;
-+
-+ rbuf = xfr->rbuf;
-+ wbuf = xfr->wbuf;
-+
-+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags))) {
-+ /* The client left. */
-+ rbuf = &drain;
-+ wbuf = &drain;
-+ sbefifo_buf_init(&drain);
-+ if (!test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags))
-+ set_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags);
-+ }
-+
-+ /* Drain the write buffer. */
-+ while ((bufn = sbefifo_buf_nbreadable(wbuf))) {
-+ ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS,
-+ &sts);
-+ if (ret)
-+ goto out;
-+
-+ devn = sbefifo_dev_nwwriteable(sts);
-+ if (devn == 0) {
-+ /* No open slot for write. Reschedule. */
-+ sbefifo->poll_timer.expires = jiffies +
-+ msecs_to_jiffies(500);
-+ add_timer(&sbefifo->poll_timer);
-+ goto out_unlock;
-+ }
-+
-+ devn = min_t(size_t, devn, bufn >> 2);
-+ for (i = 0; i < devn; i++) {
-+ ret = sbefifo_writew(sbefifo, *wbuf->rpos);
-+ if (ret)
-+ goto out;
-+
-+ sbefifo_buf_readnb(wbuf, 1 << 2);
-+ }
-+ }
-+
-+ /* Send EOT if the writer is finished. */
-+ if (test_and_clear_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags)) {
-+ ret = sbefifo_outw(sbefifo,
-+ SBEFIFO_UP | SBEFIFO_EOT_RAISE,
-+ SBEFIFO_EOT_MAGIC);
-+ if (ret)
-+ goto out;
-+
-+ /* Inform reschedules that the writer is finished. */
-+ set_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags);
-+ }
-+
-+ /* Nothing left to do if the writer is not finished. */
-+ if (!test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags))
-+ goto out;
-+
-+ /* Fill the read buffer. */
-+ while ((bufn = sbefifo_buf_nbwriteable(rbuf))) {
-+ ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts);
-+ if (ret)
-+ goto out;
-+
-+ devn = sbefifo_dev_nwreadable(sts);
-+ if (devn == 0) {
-+ /* No data yet. Reschedule. */
-+ sbefifo->poll_timer.expires = jiffies +
-+ msecs_to_jiffies(500);
-+ add_timer(&sbefifo->poll_timer);
-+ goto out_unlock;
-+ }
-+
-+ /* Fill. The EOT word is discarded. */
-+ devn = min_t(size_t, devn, bufn >> 2);
-+ eot = (sts & EOT_MASK) != 0;
-+ if (eot)
-+ devn--;
-+
-+ for (i = 0; i < devn; i++) {
-+ ret = sbefifo_readw(sbefifo, rbuf->wpos);
-+ if (ret)
-+ goto out;
-+
-+ if (likely(!test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags)))
-+ sbefifo_buf_wrotenb(rbuf, 1 << 2);
-+ }
-+
-+ if (eot) {
-+ ret = sbefifo_ack_eot(sbefifo);
-+ if (ret)
-+ goto out;
-+
-+ set_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags);
-+ list_del(&xfr->xfrs);
-+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL,
-+ &xfr->flags)))
-+ kfree(xfr);
-+ break;
-+ }
-+ }
-+
-+out:
-+ if (unlikely(ret)) {
-+ sbefifo->rc = ret;
-+ dev_err(&sbefifo->fsi_dev->dev,
-+ "Fatal bus access failure: %d\n", ret);
-+ list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
-+ kfree(xfr);
-+ INIT_LIST_HEAD(&sbefifo->xfrs);
-+
-+ } else if (eot && sbefifo_next_xfr(sbefifo)) {
-+ sbefifo_get(sbefifo);
-+ sbefifo->poll_timer.expires = jiffies;
-+ add_timer(&sbefifo->poll_timer);
-+ }
-+
-+ sbefifo_put(sbefifo);
-+ wake_up(&sbefifo->wait);
-+
-+out_unlock:
-+ spin_unlock(&sbefifo->lock);
-+}
-+
-+static int sbefifo_open(struct inode *inode, struct file *file)
-+{
-+ struct sbefifo *sbefifo = container_of(file->private_data,
-+ struct sbefifo, mdev);
-+ struct sbefifo_client *client;
-+ int ret;
-+
-+ ret = READ_ONCE(sbefifo->rc);
-+ if (ret)
-+ return ret;
-+
-+ client = sbefifo_new_client(sbefifo);
-+ if (!client)
-+ return -ENOMEM;
-+
-+ file->private_data = client;
-+
-+ return 0;
-+}
-+
-+static unsigned int sbefifo_poll(struct file *file, poll_table *wait)
-+{
-+ struct sbefifo_client *client = file->private_data;
-+ struct sbefifo *sbefifo = client->dev;
-+ unsigned int mask = 0;
-+
-+ poll_wait(file, &sbefifo->wait, wait);
-+
-+ if (READ_ONCE(sbefifo->rc))
-+ mask |= POLLERR;
-+
-+ if (sbefifo_buf_nbreadable(&client->rbuf))
-+ mask |= POLLIN;
-+
-+ if (sbefifo_buf_nbwriteable(&client->wbuf))
-+ mask |= POLLOUT;
-+
-+ return mask;
-+}
-+
-+static ssize_t sbefifo_read(struct file *file, char __user *buf,
-+ size_t len, loff_t *offset)
-+{
-+ struct sbefifo_client *client = file->private_data;
-+ struct sbefifo *sbefifo = client->dev;
-+ struct sbefifo_xfr *xfr;
-+ ssize_t ret = 0;
-+ size_t n;
-+
-+ WARN_ON(*offset);
-+
-+ if (!access_ok(VERIFY_WRITE, buf, len))
-+ return -EFAULT;
-+
-+ if ((len >> 2) << 2 != len)
-+ return -EINVAL;
-+
-+ if ((file->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client))
-+ return -EAGAIN;
-+
-+ sbefifo_get_client(client);
-+ if (wait_event_interruptible(sbefifo->wait,
-+ (ret = READ_ONCE(sbefifo->rc)) ||
-+ (n = sbefifo_buf_nbreadable(
-+ &client->rbuf)))) {
-+ sbefifo_put_client(client);
-+ return -ERESTARTSYS;
-+ }
-+ if (ret) {
-+ INIT_LIST_HEAD(&client->xfrs);
-+ sbefifo_put_client(client);
-+ return ret;
-+ }
-+
-+ n = min_t(size_t, n, len);
-+
-+ if (copy_to_user(buf, READ_ONCE(client->rbuf.rpos), n)) {
-+ sbefifo_put_client(client);
-+ return -EFAULT;
-+ }
-+
-+ if (sbefifo_buf_readnb(&client->rbuf, n)) {
-+ xfr = sbefifo_client_next_xfr(client);
-+ if (!test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags)) {
-+ /*
-+ * Fill the read buffer back up.
-+ */
-+ sbefifo_get(sbefifo);
-+ if (mod_timer(&client->dev->poll_timer, jiffies))
-+ sbefifo_put(sbefifo);
-+ } else {
-+ kfree(xfr);
-+ list_del(&xfr->client);
-+ wake_up(&sbefifo->wait);
-+ }
-+ }
-+
-+ sbefifo_put_client(client);
-+
-+ return n;
-+}
-+
-+static ssize_t sbefifo_write(struct file *file, const char __user *buf,
-+ size_t len, loff_t *offset)
-+{
-+ struct sbefifo_client *client = file->private_data;
-+ struct sbefifo *sbefifo = client->dev;
-+ struct sbefifo_xfr *xfr;
-+ ssize_t ret = 0;
-+ size_t n;
-+
-+ WARN_ON(*offset);
-+
-+ if (!access_ok(VERIFY_READ, buf, len))
-+ return -EFAULT;
-+
-+ if ((len >> 2) << 2 != len)
-+ return -EINVAL;
-+
-+ if (!len)
-+ return 0;
-+
-+ n = sbefifo_buf_nbwriteable(&client->wbuf);
-+
-+ spin_lock_irq(&sbefifo->lock);
-+ xfr = sbefifo_next_xfr(sbefifo);
-+
-+ if ((file->f_flags & O_NONBLOCK) && xfr && n < len) {
-+ spin_unlock_irq(&sbefifo->lock);
-+ return -EAGAIN;
-+ }
-+
-+ xfr = sbefifo_enq_xfr(client);
-+ if (!xfr) {
-+ spin_unlock_irq(&sbefifo->lock);
-+ return -ENOMEM;
-+ }
-+ spin_unlock_irq(&sbefifo->lock);
-+
-+ sbefifo_get_client(client);
-+
-+ /*
-+ * Partial writes are not really allowed in that EOT is sent exactly
-+ * once per write.
-+ */
-+ while (len) {
-+ if (wait_event_interruptible(sbefifo->wait,
-+ READ_ONCE(sbefifo->rc) ||
-+ (sbefifo_client_next_xfr(client) == xfr &&
-+ (n = sbefifo_buf_nbwriteable(
-+ &client->wbuf))))) {
-+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
-+ sbefifo_get(sbefifo);
-+ if (mod_timer(&sbefifo->poll_timer, jiffies))
-+ sbefifo_put(sbefifo);
-+
-+ sbefifo_put_client(client);
-+ return -ERESTARTSYS;
-+ }
-+ if (sbefifo->rc) {
-+ INIT_LIST_HEAD(&client->xfrs);
-+ sbefifo_put_client(client);
-+ return sbefifo->rc;
-+ }
-+
-+ n = min_t(size_t, n, len);
-+
-+ if (copy_from_user(READ_ONCE(client->wbuf.wpos), buf, n)) {
-+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
-+ sbefifo_get(sbefifo);
-+ if (mod_timer(&sbefifo->poll_timer, jiffies))
-+ sbefifo_put(sbefifo);
-+ sbefifo_put_client(client);
-+ return -EFAULT;
-+ }
-+
-+ sbefifo_buf_wrotenb(&client->wbuf, n);
-+ len -= n;
-+ buf += n;
-+ ret += n;
-+
-+ /*
-+ * Drain the write buffer.
-+ */
-+ sbefifo_get(sbefifo);
-+ if (mod_timer(&client->dev->poll_timer, jiffies))
-+ sbefifo_put(sbefifo);
-+ }
-+
-+ set_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags);
-+ sbefifo_put_client(client);
-+
-+ return ret;
-+}
-+
-+static int sbefifo_release(struct inode *inode, struct file *file)
-+{
-+ struct sbefifo_client *client = file->private_data;
-+ struct sbefifo *sbefifo = client->dev;
-+
-+ sbefifo_put_client(client);
-+
-+ return READ_ONCE(sbefifo->rc);
-+}
-+
-+static const struct file_operations sbefifo_fops = {
-+ .owner = THIS_MODULE,
-+ .open = sbefifo_open,
-+ .read = sbefifo_read,
-+ .write = sbefifo_write,
-+ .poll = sbefifo_poll,
-+ .release = sbefifo_release,
-+};
-+
-+static int sbefifo_probe(struct device *dev)
-+{
-+ struct fsi_device *fsi_dev = to_fsi_dev(dev);
-+ struct sbefifo *sbefifo;
-+ u32 sts;
-+ int ret;
-+
-+ dev_info(dev, "Found sbefifo device\n");
-+ sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL);
-+ if (!sbefifo)
-+ return -ENOMEM;
-+
-+ sbefifo->fsi_dev = fsi_dev;
-+
-+ ret = sbefifo_inw(sbefifo,
-+ SBEFIFO_UP | SBEFIFO_STS, &sts);
-+ if (ret)
-+ return ret;
-+ if (!(sts & SBEFIFO_EMPTY)) {
-+ dev_err(&sbefifo->fsi_dev->dev,
-+ "Found data in upstream fifo\n");
-+ return -EIO;
-+ }
-+
-+ ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts);
-+ if (ret)
-+ return ret;
-+ if (!(sts & SBEFIFO_EMPTY)) {
-+ dev_err(&sbefifo->fsi_dev->dev,
-+ "Found data in downstream fifo\n");
-+ return -EIO;
-+ }
-+
-+ sbefifo->mdev.minor = MISC_DYNAMIC_MINOR;
-+ sbefifo->mdev.fops = &sbefifo_fops;
-+ sbefifo->mdev.name = sbefifo->name;
-+ sbefifo->mdev.parent = dev;
-+ spin_lock_init(&sbefifo->lock);
-+ kref_init(&sbefifo->kref);
-+
-+ sbefifo->idx = ida_simple_get(&sbefifo_ida, 1, INT_MAX, GFP_KERNEL);
-+ snprintf(sbefifo->name, sizeof(sbefifo->name), "sbefifo%d",
-+ sbefifo->idx);
-+ init_waitqueue_head(&sbefifo->wait);
-+ INIT_LIST_HEAD(&sbefifo->xfrs);
-+
-+ /* This bit of silicon doesn't offer any interrupts... */
-+ setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer,
-+ (unsigned long)sbefifo);
-+
-+ list_add(&sbefifo->link, &sbefifo_fifos);
-+ return misc_register(&sbefifo->mdev);
-+}
-+
-+static int sbefifo_remove(struct device *dev)
-+{
-+ struct fsi_device *fsi_dev = to_fsi_dev(dev);
-+ struct sbefifo *sbefifo, *sbefifo_tmp;
-+ struct sbefifo_xfr *xfr;
-+
-+ list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) {
-+ if (sbefifo->fsi_dev != fsi_dev)
-+ continue;
-+ misc_deregister(&sbefifo->mdev);
-+ list_del(&sbefifo->link);
-+ ida_simple_remove(&sbefifo_ida, sbefifo->idx);
-+
-+ if (del_timer_sync(&sbefifo->poll_timer))
-+ sbefifo_put(sbefifo);
-+
-+ spin_lock(&sbefifo->lock);
-+ list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
-+ kfree(xfr);
-+ spin_unlock(&sbefifo->lock);
-+
-+ WRITE_ONCE(sbefifo->rc, -ENODEV);
-+
-+ wake_up(&sbefifo->wait);
-+ sbefifo_put(sbefifo);
-+ }
-+
-+ return 0;
-+}
-+
-+static struct fsi_device_id sbefifo_ids[] = {
-+ {
-+ .engine_type = FSI_ENGID_SBE,
-+ .version = FSI_VERSION_ANY,
-+ },
-+ { 0 }
-+};
-+
-+static struct fsi_driver sbefifo_drv = {
-+ .id_table = sbefifo_ids,
-+ .drv = {
-+ .name = DEVICE_NAME,
-+ .bus = &fsi_bus_type,
-+ .probe = sbefifo_probe,
-+ .remove = sbefifo_remove,
-+ }
-+};
-+
-+static int sbefifo_init(void)
-+{
-+ INIT_LIST_HEAD(&sbefifo_fifos);
-+ return fsi_driver_register(&sbefifo_drv);
-+}
-+
-+static void sbefifo_exit(void)
-+{
-+ fsi_driver_unregister(&sbefifo_drv);
-+}
-+
-+module_init(sbefifo_init);
-+module_exit(sbefifo_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Brad Bishop <bradleyb@fuzziesquirrel.com>");
-+MODULE_DESCRIPTION("Linux device interface to the POWER self boot engine");
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch
deleted file mode 100644
index f38a6a4..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch
+++ /dev/null
@@ -1,326 +0,0 @@
-From patchwork Wed May 10 15:52:37 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux, dev-4.10, v2,
- 1/6] drivers: i2c: Add FSI-attached I2C master algorithm
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760697
-Message-Id: <1494431562-25101-2-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
-Date: Wed, 10 May 2017 10:52:37 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Initial startup code for the I2C algorithm to drive the I2C master
-located on POWER CPUs over FSI bus.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/Makefile | 2 +-
- drivers/i2c/busses/Kconfig | 11 ++
- drivers/i2c/busses/Makefile | 1 +
- drivers/i2c/busses/i2c-fsi.c | 245 +++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 258 insertions(+), 1 deletion(-)
- create mode 100644 drivers/i2c/busses/i2c-fsi.c
-
-diff --git a/drivers/Makefile b/drivers/Makefile
-index 67ce51d..278f109 100644
---- a/drivers/Makefile
-+++ b/drivers/Makefile
-@@ -105,6 +105,7 @@ obj-$(CONFIG_SERIO) += input/serio/
- obj-$(CONFIG_GAMEPORT) += input/gameport/
- obj-$(CONFIG_INPUT) += input/
- obj-$(CONFIG_RTC_LIB) += rtc/
-+obj-$(CONFIG_FSI) += fsi/
- obj-y += i2c/ media/
- obj-$(CONFIG_PPS) += pps/
- obj-y += ptp/
-@@ -173,4 +174,3 @@ obj-$(CONFIG_STM) += hwtracing/stm/
- obj-$(CONFIG_ANDROID) += android/
- obj-$(CONFIG_NVMEM) += nvmem/
- obj-$(CONFIG_FPGA) += fpga/
--obj-$(CONFIG_FSI) += fsi/
-diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
-index 7e34901d..0c714e0 100644
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -1245,4 +1245,15 @@ config I2C_OPAL
- This driver can also be built as a module. If so, the module will be
- called as i2c-opal.
-
-+config I2C_FSI
-+ tristate "FSI I2C driver"
-+ depends on FSI
-+ help
-+ Driver for FSI bus attached I2C masters. These are I2C masters that
-+ are connected to the system over a FSI bus, instead of the more
-+ common PCI or MMIO interface.
-+
-+ This driver can also be built as a module. If so, the module will be
-+ called as i2c-fsi.
-+
- endmenu
-diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
-index 5798b4e..547773b 100644
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -124,5 +124,6 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
- obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
- obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
- obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
-+obj-$(CONFIG_I2C_FSI) += i2c-fsi.o
-
- ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
-diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
-new file mode 100644
-index 0000000..3c1087d
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-fsi.c
-@@ -0,0 +1,245 @@
-+/*
-+ * Copyright 2017 IBM Corporation
-+ *
-+ * Eddie James <eajames@us.ibm.com>
-+ *
-+ * 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/fsi.h>
-+#include <linux/i2c.h>
-+#include <linux/jiffies.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/sched.h>
-+#include <linux/semaphore.h>
-+#include <linux/wait.h>
-+
-+#define FSI_ENGID_I2C_FSI 0x7
-+
-+/* Find left shift from first set bit in m */
-+#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1ULL)
-+
-+/* Extract field m from v */
-+#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
-+
-+/* Set field m of v to val */
-+#define SETFIELD(m, v, val) \
-+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
-+
-+#define I2C_DEFAULT_CLK_DIV 6
-+
-+/* i2c registers */
-+#define I2C_FSI_FIFO 0x00
-+#define I2C_FSI_CMD 0x04
-+#define I2C_FSI_MODE 0x08
-+#define I2C_FSI_WATER_MARK 0x0C
-+#define I2C_FSI_INT_MASK 0x10
-+#define I2C_FSI_INT_COND 0x14
-+#define I2C_FSI_OR_INT_MASK 0x14
-+#define I2C_FSI_INTS 0x18
-+#define I2C_FSI_AND_INT_MASK 0x18
-+#define I2C_FSI_STAT 0x1C
-+#define I2C_FSI_RESET_I2C 0x1C
-+#define I2C_FSI_ESTAT 0x20
-+#define I2C_FSI_RESET_ERR 0x20
-+#define I2C_FSI_RESID_LEN 0x24
-+#define I2C_FSI_SET_SCL 0x24
-+#define I2C_FSI_PORT_BUSY 0x28
-+#define I2C_FSI_RESET_SCL 0x2C
-+#define I2C_FSI_SET_SDA 0x30
-+#define I2C_FSI_RESET_SDA 0x34
-+
-+/* cmd register */
-+#define I2C_CMD_WITH_START 0x80000000
-+#define I2C_CMD_WITH_ADDR 0x40000000
-+#define I2C_CMD_RD_CONT 0x20000000
-+#define I2C_CMD_WITH_STOP 0x10000000
-+#define I2C_CMD_FORCELAUNCH 0x08000000
-+#define I2C_CMD_ADDR 0x00fe0000
-+#define I2C_CMD_READ 0x00010000
-+#define I2C_CMD_LEN 0x0000ffff
-+
-+/* mode register */
-+#define I2C_MODE_CLKDIV 0xffff0000
-+#define I2C_MODE_PORT 0x0000fc00
-+#define I2C_MODE_ENHANCED 0x00000008
-+#define I2C_MODE_DIAG 0x00000004
-+#define I2C_MODE_PACE_ALLOW 0x00000002
-+#define I2C_MODE_WRAP 0x00000001
-+
-+/* watermark register */
-+#define I2C_WATERMARK_HI 0x0000f000
-+#define I2C_WATERMARK_LO 0x000000f0
-+
-+#define I2C_FIFO_HI_LVL 4
-+#define I2C_FIFO_LO_LVL 4
-+
-+/* interrupt register */
-+#define I2C_INT_INV_CMD 0x00008000
-+#define I2C_INT_PARITY 0x00004000
-+#define I2C_INT_BE_OVERRUN 0x00002000
-+#define I2C_INT_BE_ACCESS 0x00001000
-+#define I2C_INT_LOST_ARB 0x00000800
-+#define I2C_INT_NACK 0x00000400
-+#define I2C_INT_DAT_REQ 0x00000200
-+#define I2C_INT_CMD_COMP 0x00000100
-+#define I2C_INT_STOP_ERR 0x00000080
-+#define I2C_INT_BUSY 0x00000040
-+#define I2C_INT_IDLE 0x00000020
-+
-+#define I2C_INT_ENABLE 0x0000ff80
-+#define I2C_INT_ERR 0x0000fcc0
-+
-+/* status register */
-+#define I2C_STAT_INV_CMD 0x80000000
-+#define I2C_STAT_PARITY 0x40000000
-+#define I2C_STAT_BE_OVERRUN 0x20000000
-+#define I2C_STAT_BE_ACCESS 0x10000000
-+#define I2C_STAT_LOST_ARB 0x08000000
-+#define I2C_STAT_NACK 0x04000000
-+#define I2C_STAT_DAT_REQ 0x02000000
-+#define I2C_STAT_CMD_COMP 0x01000000
-+#define I2C_STAT_STOP_ERR 0x00800000
-+#define I2C_STAT_MAX_PORT 0x000f0000
-+#define I2C_STAT_ANY_INT 0x00008000
-+#define I2C_STAT_SCL_IN 0x00000800
-+#define I2C_STAT_SDA_IN 0x00000400
-+#define I2C_STAT_PORT_BUSY 0x00000200
-+#define I2C_STAT_SELF_BUSY 0x00000100
-+#define I2C_STAT_FIFO_COUNT 0x000000ff
-+
-+#define I2C_STAT_ERR 0xfc800000
-+#define I2C_STAT_ANY_RESP 0xff800000
-+
-+/* extended status register */
-+#define I2C_ESTAT_FIFO_SZ 0xff000000
-+#define I2C_ESTAT_SCL_IN_SY 0x00008000
-+#define I2C_ESTAT_SDA_IN_SY 0x00004000
-+#define I2C_ESTAT_S_SCL 0x00002000
-+#define I2C_ESTAT_S_SDA 0x00001000
-+#define I2C_ESTAT_M_SCL 0x00000800
-+#define I2C_ESTAT_M_SDA 0x00000400
-+#define I2C_ESTAT_HI_WATER 0x00000200
-+#define I2C_ESTAT_LO_WATER 0x00000100
-+#define I2C_ESTAT_PORT_BUSY 0x00000080
-+#define I2C_ESTAT_SELF_BUSY 0x00000040
-+#define I2C_ESTAT_VERSION 0x0000001f
-+
-+struct fsi_i2c_master {
-+ struct fsi_device *fsi;
-+ u8 fifo_size;
-+};
-+
-+static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
-+ u32 *data)
-+{
-+ int rc;
-+ u32 raw_data;
-+
-+ rc = fsi_device_read(fsi, reg, &raw_data, sizeof(raw_data));
-+ if (rc)
-+ return rc;
-+
-+ *data = be32_to_cpu(raw_data);
-+
-+ return 0;
-+}
-+
-+static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg,
-+ u32 *data)
-+{
-+ u32 raw_data = cpu_to_be32(*data);
-+
-+ return fsi_device_write(fsi, reg, &raw_data, sizeof(raw_data));
-+}
-+
-+static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
-+{
-+ int rc;
-+ u32 mode = I2C_MODE_ENHANCED, extended_status, watermark = 0;
-+ u32 interrupt = 0;
-+
-+ /* since we use polling, disable interrupts */
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt);
-+ if (rc)
-+ return rc;
-+
-+ mode = SETFIELD(I2C_MODE_CLKDIV, mode, I2C_DEFAULT_CLK_DIV);
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status);
-+ if (rc)
-+ return rc;
-+
-+ i2c->fifo_size = GETFIELD(I2C_ESTAT_FIFO_SZ, extended_status);
-+ watermark = SETFIELD(I2C_WATERMARK_HI, watermark,
-+ i2c->fifo_size - I2C_FIFO_HI_LVL);
-+ watermark = SETFIELD(I2C_WATERMARK_LO, watermark,
-+ I2C_FIFO_LO_LVL);
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark);
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
-+ int num)
-+{
-+ return -ENOSYS;
-+}
-+
-+static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
-+{
-+ return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_10BIT_ADDR;
-+}
-+
-+static const struct i2c_algorithm fsi_i2c_algorithm = {
-+ .master_xfer = fsi_i2c_xfer,
-+ .functionality = fsi_i2c_functionality,
-+};
-+
-+static int fsi_i2c_probe(struct device *dev)
-+{
-+ struct fsi_i2c_master *i2c;
-+ int rc;
-+
-+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
-+ if (!i2c)
-+ return -ENOMEM;
-+
-+ i2c->fsi = to_fsi_dev(dev);
-+
-+ rc = fsi_i2c_dev_init(i2c);
-+ if (rc)
-+ return rc;
-+
-+ dev_set_drvdata(dev, i2c);
-+
-+ return 0;
-+}
-+
-+static const struct fsi_device_id fsi_i2c_ids[] = {
-+ { FSI_ENGID_I2C_FSI, FSI_VERSION_ANY },
-+ { 0 }
-+};
-+
-+static struct fsi_driver fsi_i2c_driver = {
-+ .id_table = fsi_i2c_ids,
-+ .drv = {
-+ .name = "i2c_master_fsi",
-+ .bus = &fsi_bus_type,
-+ .probe = fsi_i2c_probe,
-+ },
-+};
-+
-+module_fsi_driver(fsi_i2c_driver);
-+
-+MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>");
-+MODULE_DESCRIPTION("FSI attached I2C master");
-+MODULE_LICENSE("GPL");
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch
deleted file mode 100644
index 20f66bf..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch
+++ /dev/null
@@ -1,194 +0,0 @@
-From patchwork Wed May 10 15:52:38 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux, dev-4.10, v2,
- 2/6] drivers: i2c: Add port structure to FSI algorithm
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760696
-Message-Id: <1494431562-25101-3-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
-Date: Wed, 10 May 2017 10:52:38 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Add and initialize I2C adapters for each port on the FSI-attached I2C
-master. Ports are defined in the devicetree.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/i2c/busses/i2c-fsi.c | 113 ++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 112 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
-index 3c1087d..cdebc99 100644
---- a/drivers/i2c/busses/i2c-fsi.c
-+++ b/drivers/i2c/busses/i2c-fsi.c
-@@ -30,6 +30,7 @@
- #define SETFIELD(m, v, val) \
- (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
-
-+#define I2C_MASTER_NR_OFFSET 100
- #define I2C_DEFAULT_CLK_DIV 6
-
- /* i2c registers */
-@@ -131,9 +132,21 @@
-
- struct fsi_i2c_master {
- struct fsi_device *fsi;
-+ int idx;
- u8 fifo_size;
-+ struct list_head ports;
-+ struct ida ida;
- };
-
-+struct fsi_i2c_port {
-+ struct list_head list;
-+ struct i2c_adapter adapter;
-+ struct fsi_i2c_master *master;
-+ u16 port;
-+};
-+
-+static DEFINE_IDA(fsi_i2c_ida);
-+
- static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
- u32 *data)
- {
-@@ -188,9 +201,44 @@ static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
- return rc;
- }
-
-+static int fsi_i2c_set_port(struct fsi_i2c_port *port)
-+{
-+ int rc;
-+ struct fsi_device *fsi = port->master->fsi;
-+ u32 mode, dummy = 0;
-+ u16 old_port;
-+
-+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode);
-+ if (rc)
-+ return rc;
-+
-+ old_port = GETFIELD(I2C_MODE_PORT, mode);
-+
-+ if (old_port != port->port) {
-+ mode = SETFIELD(I2C_MODE_PORT, mode, port->port);
-+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode);
-+ if (rc)
-+ return rc;
-+
-+ /* reset engine when port is changed */
-+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ return rc;
-+}
-+
- static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
- {
-+ int rc;
-+ struct fsi_i2c_port *port = adap->algo_data;
-+
-+ rc = fsi_i2c_set_port(port);
-+ if (rc)
-+ return rc;
-+
- return -ENOSYS;
- }
-
-@@ -207,13 +255,59 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
- static int fsi_i2c_probe(struct device *dev)
- {
- struct fsi_i2c_master *i2c;
-- int rc;
-+ struct fsi_i2c_port *port;
-+ struct device_node *np;
-+ int rc, idx;
-+ u32 port_no;
-
- i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
- if (!i2c)
- return -ENOMEM;
-
- i2c->fsi = to_fsi_dev(dev);
-+ i2c->idx = ida_simple_get(&fsi_i2c_ida, 1, INT_MAX, GFP_KERNEL);
-+ ida_init(&i2c->ida);
-+ INIT_LIST_HEAD(&i2c->ports);
-+
-+ if (dev->of_node) {
-+ /* add adapter for each i2c port of the master */
-+ for_each_child_of_node(dev->of_node, np) {
-+ rc = of_property_read_u32(np, "port", &port_no);
-+ if (rc || port_no > 0xFFFF)
-+ continue;
-+
-+ /* make sure we don't overlap index with a buggy dts */
-+ idx = ida_simple_get(&i2c->ida, port_no,
-+ port_no + 1, GFP_KERNEL);
-+ if (idx < 0)
-+ continue;
-+
-+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
-+ if (!port)
-+ return -ENOMEM;
-+
-+ port->master = i2c;
-+ port->port = (u16)port_no;
-+
-+ port->adapter.owner = THIS_MODULE;
-+ port->adapter.dev.parent = dev;
-+ port->adapter.algo = &fsi_i2c_algorithm;
-+ port->adapter.algo_data = port;
-+ /* number ports uniquely */
-+ port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) +
-+ port_no;
-+
-+ snprintf(port->adapter.name,
-+ sizeof(port->adapter.name),
-+ "fsi_i2c-%u", port_no);
-+
-+ rc = i2c_add_numbered_adapter(&port->adapter);
-+ if (rc < 0)
-+ return rc;
-+
-+ list_add(&port->list, &i2c->ports);
-+ }
-+ }
-
- rc = fsi_i2c_dev_init(i2c);
- if (rc)
-@@ -224,6 +318,22 @@ static int fsi_i2c_probe(struct device *dev)
- return 0;
- }
-
-+static int fsi_i2c_remove(struct device *dev)
-+{
-+ struct fsi_i2c_master *i2c = dev_get_drvdata(dev);
-+ struct fsi_i2c_port *port;
-+
-+ list_for_each_entry(port, &i2c->ports, list) {
-+ i2c_del_adapter(&port->adapter);
-+ }
-+
-+ ida_destroy(&i2c->ida);
-+
-+ ida_simple_remove(&fsi_i2c_ida, i2c->idx);
-+
-+ return 0;
-+}
-+
- static const struct fsi_device_id fsi_i2c_ids[] = {
- { FSI_ENGID_I2C_FSI, FSI_VERSION_ANY },
- { 0 }
-@@ -235,6 +345,7 @@ static int fsi_i2c_probe(struct device *dev)
- .name = "i2c_master_fsi",
- .bus = &fsi_bus_type,
- .probe = fsi_i2c_probe,
-+ .remove = fsi_i2c_remove,
- },
- };
-
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch
deleted file mode 100644
index 50410ff..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch
+++ /dev/null
@@ -1,243 +0,0 @@
-From patchwork Wed May 10 15:52:39 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux, dev-4.10, v2,
- 3/6] drivers: i2c: Add transfer implementation for FSI algorithm
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760702
-Message-Id: <1494431562-25101-4-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
-Date: Wed, 10 May 2017 10:52:39 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Execute I2C transfers from the FSI-attached I2C master. Use polling
-instead of interrupts as we have no hardware IRQ over FSI.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/i2c/busses/i2c-fsi.c | 193 ++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 191 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
-index cdebc99..f690b16 100644
---- a/drivers/i2c/busses/i2c-fsi.c
-+++ b/drivers/i2c/busses/i2c-fsi.c
-@@ -143,6 +143,7 @@ struct fsi_i2c_port {
- struct i2c_adapter adapter;
- struct fsi_i2c_master *master;
- u16 port;
-+ u16 xfrd;
- };
-
- static DEFINE_IDA(fsi_i2c_ida);
-@@ -229,17 +230,205 @@ static int fsi_i2c_set_port(struct fsi_i2c_port *port)
- return rc;
- }
-
-+static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg,
-+ bool stop)
-+{
-+ int rc;
-+ struct fsi_i2c_master *i2c = port->master;
-+ u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR;
-+
-+ port->xfrd = 0;
-+
-+ if (msg->flags & I2C_M_RD)
-+ cmd |= I2C_CMD_READ;
-+
-+ if (stop || msg->flags & I2C_M_STOP)
-+ cmd |= I2C_CMD_WITH_STOP;
-+
-+ cmd = SETFIELD(I2C_CMD_ADDR, cmd, msg->addr >> 1);
-+ cmd = SETFIELD(I2C_CMD_LEN, cmd, msg->len);
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd);
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
-+ u8 fifo_count)
-+{
-+ int write;
-+ int rc = 0;
-+ struct fsi_i2c_master *i2c = port->master;
-+ int bytes_to_write = i2c->fifo_size - fifo_count;
-+ int bytes_remaining = msg->len - port->xfrd;
-+
-+ if (bytes_to_write > bytes_remaining)
-+ bytes_to_write = bytes_remaining;
-+
-+ while (bytes_to_write > 0) {
-+ write = bytes_to_write;
-+ /* fsi limited to max 4 byte aligned ops */
-+ if (bytes_to_write > 4)
-+ write = 4;
-+ else if (write == 3)
-+ write = 2;
-+
-+ rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO,
-+ &msg->buf[port->xfrd], write);
-+ if (rc)
-+ return rc;
-+
-+ port->xfrd += write;
-+ bytes_to_write -= write;
-+ }
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
-+ u8 fifo_count)
-+{
-+ int read;
-+ int rc = 0;
-+ struct fsi_i2c_master *i2c = port->master;
-+ int xfr_remaining = msg->len - port->xfrd;
-+ u32 dummy;
-+
-+ while (fifo_count) {
-+ read = fifo_count;
-+ /* fsi limited to max 4 byte aligned ops */
-+ if (fifo_count > 4)
-+ read = 4;
-+ else if (read == 3)
-+ read = 2;
-+
-+ if (xfr_remaining) {
-+ if (xfr_remaining < read)
-+ read = xfr_remaining;
-+
-+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO,
-+ &msg->buf[port->xfrd], read);
-+ if (rc)
-+ return rc;
-+
-+ port->xfrd += read;
-+ xfr_remaining -= read;
-+ } else {
-+ /* no more buffer but data in fifo, need to clear it */
-+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy,
-+ read);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ fifo_count -= read;
-+ }
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_handle_status(struct fsi_i2c_port *port,
-+ struct i2c_msg *msg, u32 status)
-+{
-+ int rc;
-+ u8 fifo_count;
-+ struct fsi_i2c_master *i2c = port->master;
-+ u32 dummy = 0;
-+
-+ if (status & I2C_STAT_ERR) {
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ if (status & I2C_STAT_NACK)
-+ return -EFAULT;
-+
-+ return -EIO;
-+ }
-+
-+ if (status & I2C_STAT_DAT_REQ) {
-+ fifo_count = GETFIELD(I2C_STAT_FIFO_COUNT, status);
-+
-+ if (msg->flags & I2C_M_RD)
-+ rc = fsi_i2c_read_fifo(port, msg, fifo_count);
-+ else
-+ rc = fsi_i2c_write_fifo(port, msg, fifo_count);
-+
-+ return rc;
-+ }
-+
-+ if (status & I2C_STAT_CMD_COMP) {
-+ if (port->xfrd < msg->len)
-+ rc = -ENODATA;
-+ else
-+ rc = msg->len;
-+ }
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg,
-+ unsigned long timeout)
-+{
-+ const unsigned long local_timeout = 2; /* jiffies */
-+ u32 status = 0;
-+ int rc;
-+
-+ do {
-+ rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT,
-+ &status);
-+ if (rc)
-+ return rc;
-+
-+ if (status & I2C_STAT_ANY_RESP) {
-+ rc = fsi_i2c_handle_status(port, msg, status);
-+ if (rc < 0)
-+ return rc;
-+
-+ /* cmd complete and all data xfrd */
-+ if (rc == msg->len)
-+ return 0;
-+
-+ /* need to xfr more data, but maybe don't need wait */
-+ continue;
-+ }
-+
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(local_timeout);
-+ timeout = (timeout < local_timeout) ? 0 :
-+ timeout - local_timeout;
-+ } while (timeout);
-+
-+ return -ETIME;
-+}
-+
- static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
- {
-- int rc;
-+ int i, rc;
-+ unsigned long start_time;
- struct fsi_i2c_port *port = adap->algo_data;
-+ struct i2c_msg *msg;
-
- rc = fsi_i2c_set_port(port);
- if (rc)
- return rc;
-
-- return -ENOSYS;
-+ for (i = 0; i < num; ++i) {
-+ msg = msgs + i;
-+ start_time = jiffies;
-+
-+ rc = fsi_i2c_start(port, msg, i == num - 1);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_wait(port, msg,
-+ adap->timeout - (jiffies - start_time));
-+ if (rc)
-+ return rc;
-+ }
-+
-+ return 0;
- }
-
- static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch
deleted file mode 100644
index e649d62..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From patchwork Wed May 10 15:52:40 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux, dev-4.10, v2,
- 4/6] drivers: i2c: Add I2C master locking to FSI algorithm
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760699
-Message-Id: <1494431562-25101-5-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
-Date: Wed, 10 May 2017 10:52:40 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Since there are many ports per master, each with it's own adapter and
-chardev, we need some locking to prevent xfers from changing the master
-state while other xfers are in progress.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/i2c/busses/i2c-fsi.c | 41 +++++++++++++++++++++++++++++++++++++----
- 1 file changed, 37 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
-index f690b16..d757aee 100644
---- a/drivers/i2c/busses/i2c-fsi.c
-+++ b/drivers/i2c/busses/i2c-fsi.c
-@@ -136,6 +136,8 @@ struct fsi_i2c_master {
- u8 fifo_size;
- struct list_head ports;
- struct ida ida;
-+ wait_queue_head_t wait;
-+ struct semaphore lock;
- };
-
- struct fsi_i2c_port {
-@@ -171,6 +173,29 @@ static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg,
- return fsi_device_write(fsi, reg, &raw_data, sizeof(raw_data));
- }
-
-+static int fsi_i2c_lock_master(struct fsi_i2c_master *i2c, int timeout)
-+{
-+ int rc;
-+
-+ rc = down_trylock(&i2c->lock);
-+ if (!rc)
-+ return 0;
-+
-+ rc = wait_event_interruptible_timeout(i2c->wait,
-+ !down_trylock(&i2c->lock),
-+ timeout);
-+ if (rc > 0)
-+ return 0;
-+
-+ return -EBUSY;
-+}
-+
-+static void fsi_i2c_unlock_master(struct fsi_i2c_master *i2c)
-+{
-+ up(&i2c->lock);
-+ wake_up(&i2c->wait);
-+}
-+
- static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
- {
- int rc;
-@@ -410,25 +435,31 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- struct fsi_i2c_port *port = adap->algo_data;
- struct i2c_msg *msg;
-
-- rc = fsi_i2c_set_port(port);
-+ rc = fsi_i2c_lock_master(port->master, adap->timeout);
- if (rc)
- return rc;
-
-+ rc = fsi_i2c_set_port(port);
-+ if (rc)
-+ goto unlock;
-+
- for (i = 0; i < num; ++i) {
- msg = msgs + i;
- start_time = jiffies;
-
- rc = fsi_i2c_start(port, msg, i == num - 1);
- if (rc)
-- return rc;
-+ goto unlock;
-
- rc = fsi_i2c_wait(port, msg,
- adap->timeout - (jiffies - start_time));
- if (rc)
-- return rc;
-+ goto unlock;
- }
-
-- return 0;
-+unlock:
-+ fsi_i2c_unlock_master(port->master);
-+ return rc;
- }
-
- static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
-@@ -453,6 +484,8 @@ static int fsi_i2c_probe(struct device *dev)
- if (!i2c)
- return -ENOMEM;
-
-+ init_waitqueue_head(&i2c->wait);
-+ sema_init(&i2c->lock, 1);
- i2c->fsi = to_fsi_dev(dev);
- i2c->idx = ida_simple_get(&fsi_i2c_ida, 1, INT_MAX, GFP_KERNEL);
- ida_init(&i2c->ida);
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch
deleted file mode 100644
index f9fc75d..0000000
--- a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch
+++ /dev/null
@@ -1,117 +0,0 @@
-From patchwork Wed May 10 15:52:41 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [linux, dev-4.10, v2,
- 5/6] drivers: i2c: Add bus recovery for FSI algorithm
-From: eajames@linux.vnet.ibm.com
-X-Patchwork-Id: 760701
-Message-Id: <1494431562-25101-6-git-send-email-eajames@linux.vnet.ibm.com>
-To: openbmc@lists.ozlabs.org
-Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
-Date: Wed, 10 May 2017 10:52:41 -0500
-
-From: "Edward A. James" <eajames@us.ibm.com>
-
-Bus recovery should reset the engine and force block the bus 9 times
-to recover most situations.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- drivers/i2c/busses/i2c-fsi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 76 insertions(+)
-
-diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
-index d757aee..4689479 100644
---- a/drivers/i2c/busses/i2c-fsi.c
-+++ b/drivers/i2c/busses/i2c-fsi.c
-@@ -467,6 +467,80 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
- return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_10BIT_ADDR;
- }
-
-+static int fsi_i2c_low_level_recover_bus(struct fsi_i2c_master *i2c)
-+{
-+ int i, rc;
-+ u32 mode, dummy = 0;
-+
-+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
-+ if (rc)
-+ return rc;
-+
-+ mode |= I2C_MODE_DIAG;
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
-+ if (rc)
-+ return rc;
-+
-+ for (i = 0; i < 9; ++i) {
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ mode &= ~I2C_MODE_DIAG;
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
-+
-+ return rc;
-+}
-+
-+static int fsi_i2c_recover_bus(struct i2c_adapter *adap)
-+{
-+ int rc;
-+ u32 dummy = 0;
-+ struct fsi_i2c_port *port = adap->algo_data;
-+ struct fsi_i2c_master *i2c = port->master;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_dev_init(i2c);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_low_level_recover_bus(i2c);
-+ if (rc)
-+ return rc;
-+
-+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
-+
-+ return rc;
-+}
-+
-+static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = {
-+ .recover_bus = fsi_i2c_recover_bus,
-+};
-+
- static const struct i2c_algorithm fsi_i2c_algorithm = {
- .master_xfer = fsi_i2c_xfer,
- .functionality = fsi_i2c_functionality,
-@@ -514,6 +588,8 @@ static int fsi_i2c_probe(struct device *dev)
- port->adapter.owner = THIS_MODULE;
- port->adapter.dev.parent = dev;
- port->adapter.algo = &fsi_i2c_algorithm;
-+ port->adapter.bus_recovery_info =
-+ &fsi_i2c_bus_recovery_info;
- port->adapter.algo_data = port;
- /* number ports uniquely */
- port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) +
diff --git a/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch b/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch
deleted file mode 100644
index 01644c5..0000000
--- a/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From af9bc81e2158c326552c013d6591f533b69286e3 Mon Sep 17 00:00:00 2001
-From: "Edward A. James" <eajames@us.ibm.com>
-Date: Thu, 25 May 2017 09:59:09 -0500
-Subject: [PATCH linux dev-4.10 v2] arm: dts: aspeed: Add missing clock sources
- for barreleye
-
-Reorganize flash controllers into the ast2400 config. Barreleye wasn't
-booting with the new aspeed-smc driver.
-
-Signed-off-by: Edward A. James <eajames@us.ibm.com>
----
- arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts | 44 ++++++++--------------
- arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts | 52 ++++++++------------------
- arch/arm/boot/dts/aspeed-g4.dtsi | 34 +++++++++++++++++
- 3 files changed, 66 insertions(+), 64 deletions(-)
-
-diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts b/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts
-index be1f2d1..7a616bb 100644
---- a/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts
-+++ b/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts
-@@ -31,34 +31,6 @@
- };
- };
-
-- ahb {
-- bmc_pnor: fmc@1e620000 {
-- reg = < 0x1e620000 0x94
-- 0x20000000 0x02000000 >;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- compatible = "aspeed,ast2400-fmc";
-- flash@0 {
-- reg = < 0 >;
-- compatible = "jedec,spi-nor" ;
--#include "aspeed-bmc-opp-flash-layout.dtsi"
-- };
-- };
--
-- host_pnor: spi@1e630000 {
-- reg = < 0x1e630000 0x18
-- 0x30000000 0x02000000 >;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- compatible = "aspeed,ast2400-spi";
-- flash@0 {
-- reg = < 0 >;
-- compatible = "jedec,spi-nor" ;
-- label = "pnor";
-- };
-- };
-- };
--
- leds {
- compatible = "gpio-leds";
-
-@@ -76,6 +48,22 @@
- };
- };
-
-+&bmc_pnor {
-+ status = "okay";
-+ flash@0 {
-+ status = "okay";
-+ m25p,fast-read;
-+#include "aspeed-bmc-opp-flash-layout.dtsi"
-+ };
-+};
-+
-+&host_pnor {
-+ flash@0 {
-+ status = "okay";
-+ m25p,fast-read;
-+ };
-+};
-+
- &pinctrl {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_flbusy_default &pinctrl_flwp_default
-diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-index b4faa1d..e55abe6 100644
---- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
-@@ -47,42 +47,6 @@
- };
- };
-
-- ahb {
-- bmc_pnor: fmc@1e620000 {
-- reg = < 0x1e620000 0x94
-- 0x20000000 0x02000000 >;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- compatible = "aspeed,ast2400-fmc";
-- aspeed,fmc-has-dma;
-- interrupts = <19>;
-- clocks = <&clk_ahb>;
-- clock-names = "ahb";
-- flash@0 {
-- reg = < 0 >;
-- compatible = "jedec,spi-nor" ;
-- m25p,fast-read;
--#include "aspeed-bmc-opp-flash-layout.dtsi"
-- };
-- };
--
-- host_pnor: spi@1e630000 {
-- reg = < 0x1e630000 0x18
-- 0x30000000 0x02000000 >;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- compatible = "aspeed,ast2400-spi";
-- clocks = <&clk_ahb>;
-- clock-names = "ahb";
-- flash {
-- reg = < 0 >;
-- compatible = "jedec,spi-nor" ;
-- label = "pnor";
-- m25p,fast-read;
-- };
-- };
-- };
--
- gpio-fsi {
- compatible = "fsi-master-gpio", "fsi-master";
-
-@@ -94,6 +58,22 @@
- };
- };
-
-+&bmc_pnor {
-+ status = "okay";
-+ flash@0 {
-+ status = "okay";
-+ m25p,fast-read;
-+#include "aspeed-bmc-opp-flash-layout.dtsi"
-+ };
-+};
-+
-+&host_pnor {
-+ flash@0 {
-+ status = "okay";
-+ m25p,fast-read;
-+ };
-+};
-+
- &pinctrl {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_flbusy_default &pinctrl_flwp_default
-diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
-index d8827d5..9fb7889 100644
---- a/arch/arm/boot/dts/aspeed-g4.dtsi
-+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
-@@ -44,6 +44,40 @@
- #size-cells = <1>;
- ranges;
-
-+ bmc_pnor: fmc@1e620000 {
-+ reg = < 0x1e620000 0x94
-+ 0x20000000 0x02000000 >;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ compatible = "aspeed,ast2400-fmc";
-+ status = "disabled";
-+ aspeed,fmc-has-dma;
-+ interrupts = <19>;
-+ clocks = <&clk_ahb>;
-+ clock-names = "ahb";
-+ flash@0 {
-+ reg = < 0 >;
-+ compatible = "jedec,spi-nor" ;
-+ status = "disabled";
-+ };
-+ };
-+
-+ host_pnor: spi@1e630000 {
-+ reg = < 0x1e630000 0x18
-+ 0x30000000 0x02000000 >;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ compatible = "aspeed,ast2400-spi";
-+ status = "disabled";
-+ clocks = <&clk_ahb>;
-+ clock-names = "ahb";
-+ flash@0 {
-+ reg = < 0 >;
-+ compatible = "jedec,spi-nor" ;
-+ status = "disabled";
-+ };
-+ };
-+
- vic: interrupt-controller@1e6c0080 {
- compatible = "aspeed,ast2400-vic";
- interrupt-controller;
---
-1.8.3.1
-
diff --git a/common/recipes-kernel/linux/linux-obmc_4.10.bb b/common/recipes-kernel/linux/linux-obmc_4.10.bb
index 3a0dd9a..5b2cabd 100644
--- a/common/recipes-kernel/linux/linux-obmc_4.10.bb
+++ b/common/recipes-kernel/linux/linux-obmc_4.10.bb
@@ -1,6 +1,6 @@
KBRANCH ?= "dev-4.10"
-LINUX_VERSION ?= "4.10.5"
+LINUX_VERSION ?= "4.10.17"
-SRCREV="8736136e756ec127de0bbe2c7e2de683204d4512"
+SRCREV="c694e47cbc1efc2bc181b2ac7137dfda04f974c2"
require linux-obmc.inc