aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorYufeng Shen <miletus@chromium.org>2012-02-13 17:36:54 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-02-14 04:39:53 -0500
commit8a8ed1f5143b3df312e436ab15290e4a7ca6a559 (patch)
tree90067c14702ee364b47c551d1467508329521f28 /drivers/gpu
parentb1d7e4b41fd0f72ea8149056778db5d737739305 (diff)
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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c24
2 files changed, 21 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index caec1fdb7dda..8e3eb5e282a1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -313,6 +313,10 @@ typedef struct drm_i915_private {
313 u32 reg0; 313 u32 reg0;
314 } *gmbus; 314 } *gmbus;
315 315
316 /** gmbus_mutex protects against concurrent usage of the single hw gmbus
317 * controller on different i2c buses. */
318 struct mutex gmbus_mutex;
319
316 struct pci_dev *bridge_dev; 320 struct pci_dev *bridge_dev;
317 struct intel_ring_buffer ring[I915_NUM_RINGS]; 321 struct intel_ring_buffer ring[I915_NUM_RINGS];
318 uint32_t next_seqno; 322 uint32_t next_seqno;
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d30ccccb9d73..fc75d71de53b 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -233,11 +233,15 @@ gmbus_xfer(struct i2c_adapter *adapter,
233 struct intel_gmbus, 233 struct intel_gmbus,
234 adapter); 234 adapter);
235 struct drm_i915_private *dev_priv = adapter->algo_data; 235 struct drm_i915_private *dev_priv = adapter->algo_data;
236 int i, reg_offset; 236 int i, reg_offset, ret;
237 237
238 if (bus->force_bit) 238 mutex_lock(&dev_priv->gmbus_mutex);
239 return intel_i2c_quirk_xfer(dev_priv, 239
240 if (bus->force_bit) {
241 ret = intel_i2c_quirk_xfer(dev_priv,
240 bus->force_bit, msgs, num); 242 bus->force_bit, msgs, num);
243 goto out;
244 }
241 245
242 reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0; 246 reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
243 247
@@ -321,7 +325,8 @@ done:
321 * start of the next xfer, till then let it sleep. 325 * start of the next xfer, till then let it sleep.
322 */ 326 */
323 I915_WRITE(GMBUS0 + reg_offset, 0); 327 I915_WRITE(GMBUS0 + reg_offset, 0);
324 return i; 328 ret = i;
329 goto out;
325 330
326timeout: 331timeout:
327 DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", 332 DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
@@ -331,9 +336,12 @@ timeout:
331 /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ 336 /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
332 bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); 337 bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
333 if (!bus->force_bit) 338 if (!bus->force_bit)
334 return -ENOMEM; 339 ret = -ENOMEM;
335 340 else
336 return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); 341 ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
342out:
343 mutex_unlock(&dev_priv->gmbus_mutex);
344 return ret;
337} 345}
338 346
339static u32 gmbus_func(struct i2c_adapter *adapter) 347static u32 gmbus_func(struct i2c_adapter *adapter)
@@ -380,6 +388,8 @@ int intel_setup_gmbus(struct drm_device *dev)
380 if (dev_priv->gmbus == NULL) 388 if (dev_priv->gmbus == NULL)
381 return -ENOMEM; 389 return -ENOMEM;
382 390
391 mutex_init(&dev_priv->gmbus_mutex);
392
383 for (i = 0; i < GMBUS_NUM_PORTS; i++) { 393 for (i = 0; i < GMBUS_NUM_PORTS; i++) {
384 struct intel_gmbus *bus = &dev_priv->gmbus[i]; 394 struct intel_gmbus *bus = &dev_priv->gmbus[i];
385 395