summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
diff options
context:
space:
mode:
authorJason M. Bills <jason.m.bills@linux.intel.com>2020-12-08 00:45:20 +0300
committerJason M. Bills <jason.m.bills@linux.intel.com>2020-12-10 01:15:05 +0300
commit82dbc15a05125a812c140a3c8cff81c366482229 (patch)
tree9c8f1ad262a2e281f20340cf8646aca6f8596044 /meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
parent8d6ae7f2a817751fad151168fa10ce28ee0869d8 (diff)
downloadopenbmc-82dbc15a05125a812c140a3c8cff81c366482229.tar.xz
Update to internal 0.26
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch488
1 files changed, 0 insertions, 488 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
deleted file mode 100644
index 198beaa93..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
+++ /dev/null
@@ -1,488 +0,0 @@
-From ee9cee93b96b791f52295d7763985fdb10903e2b Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Date: Fri, 15 Feb 2019 16:05:09 -0800
-Subject: [PATCH] i2c: Add mux hold/unhold msg types
-
-This commit adds mux hold/unhold message types to support extended
-mux control for IPMB and MCTP devices. A hold or an unhold message
-can be added at the end of I2C message stream wrapped by
-repeated-start, also can be used as a single message independantly.
-
-This mux hold/unhold message will be delivered throughout all mux
-levels in the path. Means that if it goes to multi-level mux path,
-all muxes will be held/unheld by this message.
-
-1. Hold message
- struct i2c_msg msg;
- uint16_t timeout = 5000; // timeout in ms. 5 secs in this example.
-
- msg.addr = 0x0; // any value can be used. addr will be ignored in this packet.
- msg.flags = I2C_M_HOLD; // set this flag to indicate it's a hold message.
- msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer.
- msg.buf = (uint8_t *)&timeout; // set timeout value.
-
-2. Unhold message
- struct i2c_msg msg;
- uint16_t timeout = 0; // set 0 for an unhold message.
-
- msg.addr = 0x0; // any value can be used. addr will be ignored in this packet.
- msg.flags = I2C_M_HOLD; // set this flag to indicate it's an unhold message.
- msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer.
- msg.buf = (uint8_t *)&timeout; // set timeout value.
-
- This unhold message can be delivered to a mux adapter even when
- a bus is locked so that any holding state can be unheld
- immediately by invoking this unhold message.
-
-This patch would not be welcomed from upstream so it should be kept
-in downstream only.
-
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
----
- drivers/i2c/i2c-core-base.c | 70 +++++++++++++++++++++++++--
- drivers/i2c/i2c-core-smbus.c | 22 +++++++--
- drivers/i2c/i2c-mux.c | 109 +++++++++++++++++++++++++++++++++++++++----
- include/linux/i2c-mux.h | 3 ++
- include/linux/i2c.h | 25 ++++++++++
- include/uapi/linux/i2c.h | 1 +
- 6 files changed, 214 insertions(+), 16 deletions(-)
-
-diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
-index 5f6a4985f2bc..d1cd7afe4068 100644
---- a/drivers/i2c/i2c-core-base.c
-+++ b/drivers/i2c/i2c-core-base.c
-@@ -1297,6 +1297,25 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
- }
- EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
-
-+static void i2c_adapter_hold(struct i2c_adapter *adapter, unsigned long timeout)
-+{
-+ mutex_lock(&adapter->hold_lock);
-+ mod_timer(&adapter->hold_timer, jiffies + timeout);
-+}
-+
-+static void i2c_adapter_unhold(struct i2c_adapter *adapter)
-+{
-+ del_timer_sync(&adapter->hold_timer);
-+ mutex_unlock(&adapter->hold_lock);
-+}
-+
-+static void i2c_adapter_hold_timer_callback(struct timer_list *t)
-+{
-+ struct i2c_adapter *adapter = from_timer(adapter, t, hold_timer);
-+
-+ i2c_adapter_unhold(adapter);
-+}
-+
- static int i2c_register_adapter(struct i2c_adapter *adap)
- {
- int res = -EINVAL;
-@@ -1379,6 +1398,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
- bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
- mutex_unlock(&core_lock);
-
-+ mutex_init(&adap->hold_lock);
-+ timer_setup(&adap->hold_timer, i2c_adapter_hold_timer_callback, 0);
-+
- return 0;
-
- out_reg:
-@@ -1599,6 +1621,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
- idr_remove(&i2c_adapter_idr, adap->nr);
- mutex_unlock(&core_lock);
-
-+ i2c_adapter_unhold(adap);
-+
- /* Clear the device structure in case this adapter is ever going to be
- added again */
- memset(&adap->dev, 0, sizeof(adap->dev));
-@@ -1948,7 +1972,9 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs,
- */
- int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
-+ enum i2c_hold_msg_type hold_msg = I2C_HOLD_MSG_NONE;
- unsigned long orig_jiffies;
-+ unsigned long timeout;
- int ret, try;
-
- if (WARN_ON(!msgs || num < 1))
-@@ -1961,6 +1987,25 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
- return -EOPNOTSUPP;
-
-+ /* Do not deliver a mux hold msg to root bus adapter */
-+ if (!i2c_parent_is_i2c_adapter(adap)) {
-+ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
-+ msgs[num - 1].len,
-+ (u16 *)msgs[num - 1].buf);
-+ if (hold_msg == I2C_HOLD_MSG_SET) {
-+ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
-+ i2c_adapter_hold(adap, timeout);
-+
-+ if (--num == 0)
-+ return 0;
-+ } else if (hold_msg == I2C_HOLD_MSG_RESET) {
-+ i2c_adapter_unhold(adap);
-+ return 0;
-+ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
-+ mutex_lock(&adap->hold_lock);
-+ }
-+ }
-+
- /*
- * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets
- * enabled. This is an efficient way of keeping the for-loop from
-@@ -1997,6 +2042,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- trace_i2c_result(adap, num, ret);
- }
-
-+ if (!i2c_parent_is_i2c_adapter(adap) && hold_msg == I2C_HOLD_MSG_NONE)
-+ mutex_unlock(&adap->hold_lock);
-+
- return ret;
- }
- EXPORT_SYMBOL(__i2c_transfer);
-@@ -2015,6 +2063,7 @@ EXPORT_SYMBOL(__i2c_transfer);
- */
- int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
-+ bool do_bus_lock = true;
- int ret;
-
- if (!adap->algo->master_xfer) {
-@@ -2038,12 +2087,25 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- * one (discarding status on the second message) or errno
- * (discarding status on the first one).
- */
-- ret = __i2c_lock_bus_helper(adap);
-- if (ret)
-- return ret;
-+ /*
-+ * Do not lock a bus for delivering an unhold msg to a mux
-+ * adpater. This is just for a single length unhold msg case.
-+ */
-+ if (num == 1 && i2c_parent_is_i2c_adapter(adap) &&
-+ i2c_check_hold_msg(msgs[0].flags, msgs[0].len,
-+ (u16 *)msgs[0].buf) ==
-+ I2C_HOLD_MSG_RESET)
-+ do_bus_lock = false;
-+
-+ if (do_bus_lock) {
-+ ret = __i2c_lock_bus_helper(adap);
-+ if (ret)
-+ return ret;
-+ }
-
- ret = __i2c_transfer(adap, msgs, num);
-- i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
-+ if (do_bus_lock)
-+ i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
-
- return ret;
- }
-diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
-index 3ac426a8ab5a..f7bf95101e34 100644
---- a/drivers/i2c/i2c-core-smbus.c
-+++ b/drivers/i2c/i2c-core-smbus.c
-@@ -526,15 +526,29 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int protocol, union i2c_smbus_data *data)
- {
-+ bool do_bus_lock = true;
- s32 res;
-
-- res = __i2c_lock_bus_helper(adapter);
-- if (res)
-- return res;
-+ /*
-+ * Do not lock a bus for delivering an unhold msg to a mux adpater.
-+ * This is just for a single length unhold msg case.
-+ */
-+ if (i2c_parent_is_i2c_adapter(adapter) &&
-+ i2c_check_hold_msg(flags,
-+ protocol == I2C_SMBUS_WORD_DATA ? 2 : 0,
-+ &data->word) == I2C_HOLD_MSG_RESET)
-+ do_bus_lock = false;
-+
-+ if (do_bus_lock) {
-+ res = __i2c_lock_bus_helper(adapter);
-+ if (res)
-+ return res;
-+ }
-
- res = __i2c_smbus_xfer(adapter, addr, flags, read_write,
- command, protocol, data);
-- i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
-+ if (do_bus_lock)
-+ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
-
- return res;
- }
-diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
-index 774507b54b57..c6e433238b22 100644
---- a/drivers/i2c/i2c-mux.c
-+++ b/drivers/i2c/i2c-mux.c
-@@ -27,6 +27,7 @@
- #include <linux/of.h>
- #include <linux/slab.h>
- #include <linux/sysfs.h>
-+#include <linux/timer.h>
-
- /* multiplexer per channel data */
- struct i2c_mux_priv {
-@@ -36,21 +37,57 @@ struct i2c_mux_priv {
- u32 chan_id;
- };
-
-+static void i2c_mux_hold(struct i2c_mux_core *muxc, unsigned long timeout)
-+{
-+ mutex_lock(&muxc->hold_lock);
-+ mod_timer(&muxc->hold_timer, jiffies + timeout);
-+}
-+
-+static void i2c_mux_unhold(struct i2c_mux_core *muxc)
-+{
-+ del_timer_sync(&muxc->hold_timer);
-+ mutex_unlock(&muxc->hold_lock);
-+}
-+
-+static void i2c_mux_hold_timer_callback(struct timer_list *t)
-+{
-+ struct i2c_mux_core *muxc = from_timer(muxc, t, hold_timer);
-+
-+ i2c_mux_unhold(muxc);
-+}
-+
- static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
- struct i2c_msg msgs[], int num)
- {
- struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_mux_core *muxc = priv->muxc;
- struct i2c_adapter *parent = muxc->parent;
-+ enum i2c_hold_msg_type hold_msg;
-+ unsigned long timeout;
- int ret;
-
- /* Switch to the right mux port and perform the transfer. */
-
-+ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
-+ msgs[num - 1].len,
-+ (u16 *)msgs[num - 1].buf);
-+ if (hold_msg == I2C_HOLD_MSG_SET) {
-+ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
-+ i2c_mux_hold(muxc, timeout);
-+ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
-+ mutex_lock(&muxc->hold_lock);
-+ }
- ret = muxc->select(muxc, priv->chan_id);
- if (ret >= 0)
- ret = __i2c_transfer(parent, msgs, num);
-- if (muxc->deselect)
-- muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg != I2C_HOLD_MSG_SET) {
-+ if (muxc->deselect)
-+ muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg == I2C_HOLD_MSG_RESET)
-+ i2c_mux_unhold(muxc);
-+ else
-+ mutex_unlock(&muxc->hold_lock);
-+ }
-
- return ret;
- }
-@@ -61,15 +98,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
- struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_mux_core *muxc = priv->muxc;
- struct i2c_adapter *parent = muxc->parent;
-+ enum i2c_hold_msg_type hold_msg;
-+ unsigned long timeout;
- int ret;
-
- /* Switch to the right mux port and perform the transfer. */
-
-+ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
-+ msgs[num - 1].len,
-+ (u16 *)msgs[num - 1].buf);
-+ if (hold_msg == I2C_HOLD_MSG_SET) {
-+ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
-+ i2c_mux_hold(muxc, timeout);
-+ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
-+ mutex_lock(&muxc->hold_lock);
-+ }
- ret = muxc->select(muxc, priv->chan_id);
- if (ret >= 0)
- ret = i2c_transfer(parent, msgs, num);
-- if (muxc->deselect)
-- muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg != I2C_HOLD_MSG_SET) {
-+ if (muxc->deselect)
-+ muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg == I2C_HOLD_MSG_RESET)
-+ i2c_mux_unhold(muxc);
-+ else
-+ mutex_unlock(&muxc->hold_lock);
-+ }
-
- return ret;
- }
-@@ -82,16 +136,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
- struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_mux_core *muxc = priv->muxc;
- struct i2c_adapter *parent = muxc->parent;
-+ enum i2c_hold_msg_type hold_msg;
-+ unsigned long timeout;
- int ret;
-
- /* Select the right mux port and perform the transfer. */
-
-+ hold_msg = i2c_check_hold_msg(flags,
-+ size == I2C_SMBUS_WORD_DATA ? 2 : 0,
-+ &data->word);
-+ if (hold_msg == I2C_HOLD_MSG_SET) {
-+ timeout = msecs_to_jiffies(data->word);
-+ i2c_mux_hold(muxc, timeout);
-+ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
-+ mutex_lock(&muxc->hold_lock);
-+ }
- ret = muxc->select(muxc, priv->chan_id);
- if (ret >= 0)
- ret = __i2c_smbus_xfer(parent, addr, flags,
- read_write, command, size, data);
-- if (muxc->deselect)
-- muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg != I2C_HOLD_MSG_SET) {
-+ if (muxc->deselect)
-+ muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg == I2C_HOLD_MSG_RESET)
-+ i2c_mux_unhold(muxc);
-+ else
-+ mutex_unlock(&muxc->hold_lock);
-+ }
-
- return ret;
- }
-@@ -104,16 +175,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
- struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_mux_core *muxc = priv->muxc;
- struct i2c_adapter *parent = muxc->parent;
-+ enum i2c_hold_msg_type hold_msg;
-+ unsigned long timeout;
- int ret;
-
- /* Select the right mux port and perform the transfer. */
-
-+ hold_msg = i2c_check_hold_msg(flags,
-+ size == I2C_SMBUS_WORD_DATA ? 2 : 0,
-+ &data->word);
-+ if (hold_msg == I2C_HOLD_MSG_SET) {
-+ timeout = msecs_to_jiffies(data->word);
-+ i2c_mux_hold(muxc, timeout);
-+ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
-+ mutex_lock(&muxc->hold_lock);
-+ }
- ret = muxc->select(muxc, priv->chan_id);
- if (ret >= 0)
- ret = i2c_smbus_xfer(parent, addr, flags,
- read_write, command, size, data);
-- if (muxc->deselect)
-- muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg != I2C_HOLD_MSG_SET) {
-+ if (muxc->deselect)
-+ muxc->deselect(muxc, priv->chan_id);
-+ if (hold_msg == I2C_HOLD_MSG_RESET)
-+ i2c_mux_unhold(muxc);
-+ else
-+ mutex_unlock(&muxc->hold_lock);
-+ }
-
- return ret;
- }
-@@ -263,6 +351,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
- muxc->deselect = deselect;
- muxc->max_adapters = max_adapters;
-
-+ mutex_init(&muxc->hold_lock);
-+ timer_setup(&muxc->hold_timer, i2c_mux_hold_timer_callback, 0);
-+
- return muxc;
- }
- EXPORT_SYMBOL_GPL(i2c_mux_alloc);
-@@ -441,6 +532,8 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
- {
- char symlink_name[20];
-
-+ i2c_mux_unhold(muxc);
-+
- while (muxc->num_adapters) {
- struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
- struct i2c_mux_priv *priv = adap->algo_data;
-diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
-index c5a977320f82..47f8763d6ed2 100644
---- a/include/linux/i2c-mux.h
-+++ b/include/linux/i2c-mux.h
-@@ -27,6 +27,9 @@ struct i2c_mux_core {
- int (*select)(struct i2c_mux_core *, u32 chan_id);
- int (*deselect)(struct i2c_mux_core *, u32 chan_id);
-
-+ struct mutex hold_lock; /* mutex for channel holding */
-+ struct timer_list hold_timer;
-+
- int num_adapters;
- int max_adapters;
- struct i2c_adapter *adapter[0];
-diff --git a/include/linux/i2c.h b/include/linux/i2c.h
-index 1361637c369d..b4055d133338 100644
---- a/include/linux/i2c.h
-+++ b/include/linux/i2c.h
-@@ -711,6 +711,13 @@ struct i2c_adapter {
- const struct i2c_adapter_quirks *quirks;
-
- struct irq_domain *host_notify_domain;
-+
-+ /*
-+ * These will be used by root adpaters only. For muxes, each mux core
-+ * has these individually.
-+ */
-+ struct mutex hold_lock; /* mutex for bus holding */
-+ struct timer_list hold_timer;
- };
- #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
-
-@@ -1005,4 +1012,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha
- }
- #endif /* CONFIG_ACPI */
-
-+enum i2c_hold_msg_type {
-+ I2C_HOLD_MSG_NONE,
-+ I2C_HOLD_MSG_SET,
-+ I2C_HOLD_MSG_RESET
-+};
-+
-+static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf)
-+{
-+ if (flags & I2C_M_HOLD && len == sizeof(u16)) {
-+ if (*buf)
-+ return I2C_HOLD_MSG_SET;
-+
-+ return I2C_HOLD_MSG_RESET;
-+ }
-+
-+ return I2C_HOLD_MSG_NONE;
-+}
-+
- #endif /* _LINUX_I2C_H */
-diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
-index f71a1751cacf..a1db9b17ed36 100644
---- a/include/uapi/linux/i2c.h
-+++ b/include/uapi/linux/i2c.h
-@@ -72,6 +72,7 @@ struct i2c_msg {
- #define I2C_M_RD 0x0001 /* read data, from slave to master */
- /* I2C_M_RD is guaranteed to be 0x0001! */
- #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
-+#define I2C_M_HOLD 0x0100 /* for holding a mux path */
- #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */
- /* makes only sense in kernelspace */
- /* userspace buffers are copied anyway */
---
-2.7.4
-