Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: mux: relax locking of the top i2c adapter during mux-locked muxing

With a i2c topology like the following

GPIO ---| ------ BAT1
| v /
I2C -----+----------+---- MUX
| \
EEPROM ------ BAT2

there is a locking problem with the GPIO controller since it is a client
on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
will lock the whole i2c bus prior to attempting to switch the mux to the
correct i2c segment. In the above case, the GPIO device is an I/O expander
with an i2c interface, and since the GPIO subsystem knows nothing (and
rightfully so) about the lockless needs of the i2c mux code, this results
in a deadlock when the GPIO driver issues i2c transfers to modify the
mux.

So, observing that while it is needed to have the i2c bus locked during the
actual MUX update in order to avoid random garbage on the slave side, it
is not strictly a must to have it locked over the whole sequence of a full
select-transfer-deselect mux client operation. The mux itself needs to be
locked, so transfers to clients behind the mux are serialized, and the mux
needs to be stable during all i2c traffic (otherwise individual mux slave
segments might see garbage, or worse).

Introduce this new locking concept as "mux-locked" muxes, and call the
pre-existing mux locking scheme "parent-locked".

Modify the i2c mux locking so that muxes that are "mux-locked" locks only
the muxes on the parent adapter instead of the whole i2c bus when there is
a transfer to the slave side of the mux. This lock serializes transfers to
the slave side of the muxes on the parent adapter.

Add code to i2c-mux-gpio and i2c-mux-pinctrl that checks if all involved
gpio/pinctrl devices have a parent that is an i2c adapter in the same
adapter tree that is muxed, and request a "mux-locked mux" if that is the
case.

Modify the select-transfer-deselect code for "mux-locked" muxes so
that each of the select-transfer-deselect ops locks the mux parent
adapter individually.

Signed-off-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Peter Rosin and committed by
Wolfram Sang
6ef91fcc fa96f0cb

+205 -13
+1
drivers/i2c/i2c-core.c
··· 1540 1540 } 1541 1541 1542 1542 rt_mutex_init(&adap->bus_lock); 1543 + rt_mutex_init(&adap->mux_lock); 1543 1544 mutex_init(&adap->userspace_clients_lock); 1544 1545 INIT_LIST_HEAD(&adap->userspace_clients); 1545 1546
+139 -13
drivers/i2c/i2c-mux.c
··· 35 35 u32 chan_id; 36 36 }; 37 37 38 + static int __i2c_mux_master_xfer(struct i2c_adapter *adap, 39 + struct i2c_msg msgs[], int num) 40 + { 41 + struct i2c_mux_priv *priv = adap->algo_data; 42 + struct i2c_mux_core *muxc = priv->muxc; 43 + struct i2c_adapter *parent = muxc->parent; 44 + int ret; 45 + 46 + /* Switch to the right mux port and perform the transfer. */ 47 + 48 + ret = muxc->select(muxc, priv->chan_id); 49 + if (ret >= 0) 50 + ret = __i2c_transfer(parent, msgs, num); 51 + if (muxc->deselect) 52 + muxc->deselect(muxc, priv->chan_id); 53 + 54 + return ret; 55 + } 56 + 38 57 static int i2c_mux_master_xfer(struct i2c_adapter *adap, 39 58 struct i2c_msg msgs[], int num) 40 59 { ··· 66 47 67 48 ret = muxc->select(muxc, priv->chan_id); 68 49 if (ret >= 0) 69 - ret = __i2c_transfer(parent, msgs, num); 50 + ret = i2c_transfer(parent, msgs, num); 51 + if (muxc->deselect) 52 + muxc->deselect(muxc, priv->chan_id); 53 + 54 + return ret; 55 + } 56 + 57 + static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, 58 + u16 addr, unsigned short flags, 59 + char read_write, u8 command, 60 + int size, union i2c_smbus_data *data) 61 + { 62 + struct i2c_mux_priv *priv = adap->algo_data; 63 + struct i2c_mux_core *muxc = priv->muxc; 64 + struct i2c_adapter *parent = muxc->parent; 65 + int ret; 66 + 67 + /* Select the right mux port and perform the transfer. */ 68 + 69 + ret = muxc->select(muxc, priv->chan_id); 70 + if (ret >= 0) 71 + ret = parent->algo->smbus_xfer(parent, addr, flags, 72 + read_write, command, size, data); 70 73 if (muxc->deselect) 71 74 muxc->deselect(muxc, priv->chan_id); 72 75 ··· 109 68 110 69 ret = muxc->select(muxc, priv->chan_id); 111 70 if (ret >= 0) 112 - ret = parent->algo->smbus_xfer(parent, addr, flags, 113 - read_write, command, size, data); 71 + ret = i2c_smbus_xfer(parent, addr, flags, 72 + read_write, command, size, data); 114 73 if (muxc->deselect) 115 74 muxc->deselect(muxc, priv->chan_id); 116 75 ··· 139 98 return class; 140 99 } 141 100 101 + static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags) 102 + { 103 + struct i2c_mux_priv *priv = adapter->algo_data; 104 + struct i2c_adapter *parent = priv->muxc->parent; 105 + 106 + rt_mutex_lock(&parent->mux_lock); 107 + if (!(flags & I2C_LOCK_ROOT_ADAPTER)) 108 + return; 109 + i2c_lock_bus(parent, flags); 110 + } 111 + 112 + static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) 113 + { 114 + struct i2c_mux_priv *priv = adapter->algo_data; 115 + struct i2c_adapter *parent = priv->muxc->parent; 116 + 117 + if (!rt_mutex_trylock(&parent->mux_lock)) 118 + return 0; /* mux_lock not locked, failure */ 119 + if (!(flags & I2C_LOCK_ROOT_ADAPTER)) 120 + return 1; /* we only want mux_lock, success */ 121 + if (parent->trylock_bus(parent, flags)) 122 + return 1; /* parent locked too, success */ 123 + rt_mutex_unlock(&parent->mux_lock); 124 + return 0; /* parent not locked, failure */ 125 + } 126 + 127 + static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) 128 + { 129 + struct i2c_mux_priv *priv = adapter->algo_data; 130 + struct i2c_adapter *parent = priv->muxc->parent; 131 + 132 + if (flags & I2C_LOCK_ROOT_ADAPTER) 133 + i2c_unlock_bus(parent, flags); 134 + rt_mutex_unlock(&parent->mux_lock); 135 + } 136 + 142 137 static void i2c_parent_lock_bus(struct i2c_adapter *adapter, 143 138 unsigned int flags) 144 139 { 145 140 struct i2c_mux_priv *priv = adapter->algo_data; 146 141 struct i2c_adapter *parent = priv->muxc->parent; 147 142 148 - parent->lock_bus(parent, flags); 143 + rt_mutex_lock(&parent->mux_lock); 144 + i2c_lock_bus(parent, flags); 149 145 } 150 146 151 147 static int i2c_parent_trylock_bus(struct i2c_adapter *adapter, ··· 191 113 struct i2c_mux_priv *priv = adapter->algo_data; 192 114 struct i2c_adapter *parent = priv->muxc->parent; 193 115 194 - return parent->trylock_bus(parent, flags); 116 + if (!rt_mutex_trylock(&parent->mux_lock)) 117 + return 0; /* mux_lock not locked, failure */ 118 + if (parent->trylock_bus(parent, flags)) 119 + return 1; /* parent locked too, success */ 120 + rt_mutex_unlock(&parent->mux_lock); 121 + return 0; /* parent not locked, failure */ 195 122 } 196 123 197 124 static void i2c_parent_unlock_bus(struct i2c_adapter *adapter, ··· 205 122 struct i2c_mux_priv *priv = adapter->algo_data; 206 123 struct i2c_adapter *parent = priv->muxc->parent; 207 124 208 - parent->unlock_bus(parent, flags); 125 + i2c_unlock_bus(parent, flags); 126 + rt_mutex_unlock(&parent->mux_lock); 209 127 } 128 + 129 + struct i2c_adapter *i2c_root_adapter(struct device *dev) 130 + { 131 + struct device *i2c; 132 + struct i2c_adapter *i2c_root; 133 + 134 + /* 135 + * Walk up the device tree to find an i2c adapter, indicating 136 + * that this is an i2c client device. Check all ancestors to 137 + * handle mfd devices etc. 138 + */ 139 + for (i2c = dev; i2c; i2c = i2c->parent) { 140 + if (i2c->type == &i2c_adapter_type) 141 + break; 142 + } 143 + if (!i2c) 144 + return NULL; 145 + 146 + /* Continue up the tree to find the root i2c adapter */ 147 + i2c_root = to_i2c_adapter(i2c); 148 + while (i2c_parent_is_i2c_adapter(i2c_root)) 149 + i2c_root = i2c_parent_is_i2c_adapter(i2c_root); 150 + 151 + return i2c_root; 152 + } 153 + EXPORT_SYMBOL_GPL(i2c_root_adapter); 210 154 211 155 struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, 212 156 struct device *dev, int max_adapters, ··· 253 143 254 144 muxc->parent = parent; 255 145 muxc->dev = dev; 146 + if (flags & I2C_MUX_LOCKED) 147 + muxc->mux_locked = true; 256 148 muxc->select = select; 257 149 muxc->deselect = deselect; 258 150 muxc->max_adapters = max_adapters; ··· 288 176 /* Need to do algo dynamically because we don't know ahead 289 177 * of time what sort of physical adapter we'll be dealing with. 290 178 */ 291 - if (parent->algo->master_xfer) 292 - priv->algo.master_xfer = i2c_mux_master_xfer; 293 - if (parent->algo->smbus_xfer) 294 - priv->algo.smbus_xfer = i2c_mux_smbus_xfer; 179 + if (parent->algo->master_xfer) { 180 + if (muxc->mux_locked) 181 + priv->algo.master_xfer = i2c_mux_master_xfer; 182 + else 183 + priv->algo.master_xfer = __i2c_mux_master_xfer; 184 + } 185 + if (parent->algo->smbus_xfer) { 186 + if (muxc->mux_locked) 187 + priv->algo.smbus_xfer = i2c_mux_smbus_xfer; 188 + else 189 + priv->algo.smbus_xfer = __i2c_mux_smbus_xfer; 190 + } 295 191 priv->algo.functionality = i2c_mux_functionality; 296 192 297 193 /* Now fill out new adapter structure */ ··· 312 192 priv->adap.retries = parent->retries; 313 193 priv->adap.timeout = parent->timeout; 314 194 priv->adap.quirks = parent->quirks; 315 - priv->adap.lock_bus = i2c_parent_lock_bus; 316 - priv->adap.trylock_bus = i2c_parent_trylock_bus; 317 - priv->adap.unlock_bus = i2c_parent_unlock_bus; 195 + if (muxc->mux_locked) { 196 + priv->adap.lock_bus = i2c_mux_lock_bus; 197 + priv->adap.trylock_bus = i2c_mux_trylock_bus; 198 + priv->adap.unlock_bus = i2c_mux_unlock_bus; 199 + } else { 200 + priv->adap.lock_bus = i2c_parent_lock_bus; 201 + priv->adap.trylock_bus = i2c_parent_trylock_bus; 202 + priv->adap.unlock_bus = i2c_parent_unlock_bus; 203 + } 318 204 319 205 /* Sanity check on class */ 320 206 if (i2c_mux_parent_classes(parent) & class)
+18
drivers/i2c/muxes/i2c-mux-gpio.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/slab.h> 17 17 #include <linux/gpio.h> 18 + #include "../../gpio/gpiolib.h" 18 19 #include <linux/of_gpio.h> 19 20 20 21 struct gpiomux { ··· 138 137 struct i2c_mux_core *muxc; 139 138 struct gpiomux *mux; 140 139 struct i2c_adapter *parent; 140 + struct i2c_adapter *root; 141 141 unsigned initial_state, gpio_base; 142 142 int i, ret; 143 143 ··· 186 184 187 185 platform_set_drvdata(pdev, muxc); 188 186 187 + root = i2c_root_adapter(&parent->dev); 188 + 189 + muxc->mux_locked = true; 189 190 mux->gpio_base = gpio_base; 190 191 191 192 if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { ··· 199 194 } 200 195 201 196 for (i = 0; i < mux->data.n_gpios; i++) { 197 + struct device *gpio_dev; 198 + struct gpio_desc *gpio_desc; 199 + 202 200 ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); 203 201 if (ret) { 204 202 dev_err(&pdev->dev, "Failed to request GPIO %d\n", ··· 218 210 i++; /* gpio_request above succeeded, so must free */ 219 211 goto err_request_gpio; 220 212 } 213 + 214 + if (!muxc->mux_locked) 215 + continue; 216 + 217 + gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]); 218 + gpio_dev = &gpio_desc->gdev->dev; 219 + muxc->mux_locked = i2c_root_adapter(gpio_dev) == root; 221 220 } 221 + 222 + if (muxc->mux_locked) 223 + dev_info(&pdev->dev, "mux-locked i2c mux\n"); 222 224 223 225 for (i = 0; i < mux->data.n_values; i++) { 224 226 u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
+38
drivers/i2c/muxes/i2c-mux-pinctrl.c
··· 24 24 #include <linux/platform_device.h> 25 25 #include <linux/slab.h> 26 26 #include <linux/of.h> 27 + #include "../../pinctrl/core.h" 27 28 28 29 struct i2c_mux_pinctrl { 29 30 struct i2c_mux_pinctrl_platform_data *pdata; ··· 121 120 } 122 121 #endif 123 122 123 + static struct i2c_adapter *i2c_mux_pinctrl_root_adapter( 124 + struct pinctrl_state *state) 125 + { 126 + struct i2c_adapter *root = NULL; 127 + struct pinctrl_setting *setting; 128 + struct i2c_adapter *pin_root; 129 + 130 + list_for_each_entry(setting, &state->settings, node) { 131 + pin_root = i2c_root_adapter(setting->pctldev->dev); 132 + if (!pin_root) 133 + return NULL; 134 + if (!root) 135 + root = pin_root; 136 + else if (root != pin_root) 137 + return NULL; 138 + } 139 + 140 + return root; 141 + } 142 + 124 143 static int i2c_mux_pinctrl_probe(struct platform_device *pdev) 125 144 { 126 145 struct i2c_mux_core *muxc; 127 146 struct i2c_mux_pinctrl *mux; 147 + struct i2c_adapter *root; 128 148 int i, ret; 129 149 130 150 mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); ··· 223 201 ret = -EPROBE_DEFER; 224 202 goto err; 225 203 } 204 + 205 + root = i2c_root_adapter(&muxc->parent->dev); 206 + 207 + muxc->mux_locked = true; 208 + for (i = 0; i < mux->pdata->bus_count; i++) { 209 + if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) { 210 + muxc->mux_locked = false; 211 + break; 212 + } 213 + } 214 + if (muxc->mux_locked && mux->pdata->pinctrl_state_idle && 215 + root != i2c_mux_pinctrl_root_adapter(mux->state_idle)) 216 + muxc->mux_locked = false; 217 + 218 + if (muxc->mux_locked) 219 + dev_info(&pdev->dev, "mux-locked i2c mux\n"); 226 220 227 221 for (i = 0; i < mux->pdata->bus_count; i++) { 228 222 u32 bus = mux->pdata->base_bus_num ?
+8
include/linux/i2c-mux.h
··· 27 27 28 28 #ifdef __KERNEL__ 29 29 30 + #include <linux/bitops.h> 31 + 30 32 struct i2c_mux_core { 31 33 struct i2c_adapter *parent; 32 34 struct device *dev; 35 + bool mux_locked; 33 36 34 37 void *priv; 35 38 ··· 50 47 int (*select)(struct i2c_mux_core *, u32), 51 48 int (*deselect)(struct i2c_mux_core *, u32)); 52 49 50 + /* flags for i2c_mux_alloc */ 51 + #define I2C_MUX_LOCKED BIT(0) 52 + 53 53 static inline void *i2c_mux_priv(struct i2c_mux_core *muxc) 54 54 { 55 55 return muxc->priv; 56 56 } 57 + 58 + struct i2c_adapter *i2c_root_adapter(struct device *dev); 57 59 58 60 /* 59 61 * Called to create an i2c bus on a multiplexed bus segment.
+1
include/linux/i2c.h
··· 524 524 525 525 /* data fields that are valid for all devices */ 526 526 struct rt_mutex bus_lock; 527 + struct rt_mutex mux_lock; 527 528 528 529 int timeout; /* in jiffies */ 529 530 int retries;