mirror of https://gitee.com/openkylin/linux.git
drm/i915: Fix race condition in accessing GMBUS
GMBUS has several ports and each has it's own corresponding I2C adpater. When multiple I2C adapters call gmbus_xfer() at the same time there is a race condition in using the underlying GMBUS controller. Fixing this by adding a mutex lock when calling gmbus_xfer(). v2: Moved gmbus_mutex below intel_gmbus and added comments. Rebased to drm-intel-next-queued. Signed-off-by: Yufeng Shen <miletus@chromium.org> [danvet: Shortened the gmbus_mutex comment a bit and add the patch revision comment to the commit message.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
b1d7e4b41f
commit
8a8ed1f514
|
@ -313,6 +313,10 @@ typedef struct drm_i915_private {
|
|||
u32 reg0;
|
||||
} *gmbus;
|
||||
|
||||
/** gmbus_mutex protects against concurrent usage of the single hw gmbus
|
||||
* controller on different i2c buses. */
|
||||
struct mutex gmbus_mutex;
|
||||
|
||||
struct pci_dev *bridge_dev;
|
||||
struct intel_ring_buffer ring[I915_NUM_RINGS];
|
||||
uint32_t next_seqno;
|
||||
|
|
|
@ -233,11 +233,15 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
|||
struct intel_gmbus,
|
||||
adapter);
|
||||
struct drm_i915_private *dev_priv = adapter->algo_data;
|
||||
int i, reg_offset;
|
||||
int i, reg_offset, ret;
|
||||
|
||||
if (bus->force_bit)
|
||||
return intel_i2c_quirk_xfer(dev_priv,
|
||||
mutex_lock(&dev_priv->gmbus_mutex);
|
||||
|
||||
if (bus->force_bit) {
|
||||
ret = intel_i2c_quirk_xfer(dev_priv,
|
||||
bus->force_bit, msgs, num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
|
||||
|
||||
|
@ -321,7 +325,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
|||
* start of the next xfer, till then let it sleep.
|
||||
*/
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
return i;
|
||||
ret = i;
|
||||
goto out;
|
||||
|
||||
timeout:
|
||||
DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
|
||||
|
@ -331,9 +336,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
|||
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
|
||||
bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
|
||||
if (!bus->force_bit)
|
||||
return -ENOMEM;
|
||||
|
||||
return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
|
||||
out:
|
||||
mutex_unlock(&dev_priv->gmbus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 gmbus_func(struct i2c_adapter *adapter)
|
||||
|
@ -380,6 +388,8 @@ int intel_setup_gmbus(struct drm_device *dev)
|
|||
if (dev_priv->gmbus == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev_priv->gmbus_mutex);
|
||||
|
||||
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
|
||||
|
|
Loading…
Reference in New Issue