|
Thomas Zimmermann |
ebf85e |
From a85066840d29fc68d95ce7dbd6bcf15ef2775d66 Mon Sep 17 00:00:00 2001
|
|
Thomas Zimmermann |
ebf85e |
From: Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
Thomas Zimmermann |
ebf85e |
Date: Wed, 26 Jul 2017 15:26:47 +0200
|
|
Thomas Zimmermann |
ebf85e |
Subject: [PATCH] drm/i915: Rework sdvo proxy i2c locking
|
|
Thomas Zimmermann |
ebf85e |
Git-commit: a85066840d29fc68d95ce7dbd6bcf15ef2775d66
|
|
Thomas Zimmermann |
ebf85e |
Patch-mainline: v4.14-rc1
|
|
Thomas Zimmermann |
ebf85e |
References: FATE#322643 bsc#1055900
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
lockdep complaints about a locking recursion for the i2c bus lock
|
|
Thomas Zimmermann |
ebf85e |
because both the sdvo ddc proxy bus and the gmbus nested within use
|
|
Thomas Zimmermann |
ebf85e |
the same locking class. It's not really a deadlock since we never nest
|
|
Thomas Zimmermann |
ebf85e |
the other way round, but it's annoying.
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
Fix it by pulling the gmbus locking into the i2c lock_ops for both
|
|
Thomas Zimmermann |
ebf85e |
i2c_adapater and making sure that the ddc_proxy_xfer function is
|
|
Thomas Zimmermann |
ebf85e |
entirely lockless.
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
Re-layouting the extracted function resulted in some whitespace
|
|
Thomas Zimmermann |
ebf85e |
cleanups, I figured we might as well keep them.
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
V2: Review from Chris:
|
|
Thomas Zimmermann |
ebf85e |
- s/locked/unlocked/ since I got the naming backwards
|
|
Thomas Zimmermann |
ebf85e |
- Use the vfuncs of the proxied adatper instead of re-rolling copies.
|
|
Thomas Zimmermann |
ebf85e |
That's more consistent with the other proxying we're doing.
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
Cc: Chris Wilson <chris@chris-wilson.co.uk>
|
|
Thomas Zimmermann |
ebf85e |
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
|
|
Thomas Zimmermann |
ebf85e |
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
|
|
Thomas Zimmermann |
ebf85e |
Link: https://patchwork.freedesktop.org/patch/msgid/20170726132647.31833-1-daniel.vetter@ffwll.ch
|
|
Thomas Zimmermann |
ebf85e |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
---
|
|
Thomas Zimmermann |
ebf85e |
drivers/gpu/drm/i915/intel_i2c.c | 36 ++++++++++++++++++++--
|
|
Thomas Zimmermann |
ebf85e |
drivers/gpu/drm/i915/intel_sdvo.c | 62 ++++++++++++++++++++++++++++++--------
|
|
Thomas Zimmermann |
ebf85e |
2 files changed, 84 insertions(+), 14 deletions(-)
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
--- a/drivers/gpu/drm/i915/intel_i2c.c
|
|
Thomas Zimmermann |
ebf85e |
+++ b/drivers/gpu/drm/i915/intel_i2c.c
|
|
Thomas Zimmermann |
ebf85e |
@@ -592,7 +592,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
int ret;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
|
|
Thomas Zimmermann |
ebf85e |
- mutex_lock(&dev_priv->gmbus_mutex);
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
if (bus->force_bit) {
|
|
Thomas Zimmermann |
ebf85e |
ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
|
|
Thomas Zimmermann |
ebf85e |
@@ -604,7 +603,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
|
|
Thomas Zimmermann |
ebf85e |
}
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
- mutex_unlock(&dev_priv->gmbus_mutex);
|
|
Thomas Zimmermann |
ebf85e |
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
return ret;
|
|
Thomas Zimmermann |
ebf85e |
@@ -624,6 +622,39 @@ static const struct i2c_algorithm gmbus_
|
|
Thomas Zimmermann |
ebf85e |
.functionality = gmbus_func
|
|
Thomas Zimmermann |
ebf85e |
};
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
+static void gmbus_lock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_gmbus *bus = to_intel_gmbus(adapter);
|
|
Thomas Zimmermann |
ebf85e |
+ struct drm_i915_private *dev_priv = bus->dev_priv;
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+ mutex_lock(&dev_priv->gmbus_mutex);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+static int gmbus_trylock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_gmbus *bus = to_intel_gmbus(adapter);
|
|
Thomas Zimmermann |
ebf85e |
+ struct drm_i915_private *dev_priv = bus->dev_priv;
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+ return mutex_trylock(&dev_priv->gmbus_mutex);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+static void gmbus_unlock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_gmbus *bus = to_intel_gmbus(adapter);
|
|
Thomas Zimmermann |
ebf85e |
+ struct drm_i915_private *dev_priv = bus->dev_priv;
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+ mutex_unlock(&dev_priv->gmbus_mutex);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+const struct i2c_lock_operations gmbus_lock_ops = {
|
|
Thomas Zimmermann |
ebf85e |
+ .lock_bus = gmbus_lock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+ .trylock_bus = gmbus_trylock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+ .unlock_bus = gmbus_unlock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+};
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
/**
|
|
Thomas Zimmermann |
ebf85e |
* intel_gmbus_setup - instantiate all Intel i2c GMBuses
|
|
Thomas Zimmermann |
ebf85e |
* @dev_priv: i915 device private
|
|
Thomas Zimmermann |
ebf85e |
@@ -665,6 +696,7 @@ int intel_setup_gmbus(struct drm_i915_pr
|
|
Thomas Zimmermann |
ebf85e |
bus->dev_priv = dev_priv;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
bus->adapter.algo = &gmbus_algorithm;
|
|
Thomas Zimmermann |
ebf85e |
+ bus->adapter.lock_ops = &gmbus_lock_ops;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
/*
|
|
Thomas Zimmermann |
ebf85e |
* We wish to retry with bit banging
|
|
Thomas Zimmermann |
ebf85e |
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
|
Thomas Zimmermann |
ebf85e |
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
|
Thomas Zimmermann |
ebf85e |
@@ -451,23 +451,24 @@ static const char * const cmd_status_nam
|
|
Thomas Zimmermann |
ebf85e |
"Scaling not supported"
|
|
Thomas Zimmermann |
ebf85e |
};
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
|
|
Thomas Zimmermann |
ebf85e |
- const void *args, int args_len)
|
|
Thomas Zimmermann |
ebf85e |
+static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
|
|
Thomas Zimmermann |
ebf85e |
+ const void *args, int args_len,
|
|
Thomas Zimmermann |
ebf85e |
+ bool unlocked)
|
|
Thomas Zimmermann |
ebf85e |
{
|
|
Thomas Zimmermann |
ebf85e |
u8 *buf, status;
|
|
Thomas Zimmermann |
ebf85e |
struct i2c_msg *msgs;
|
|
Thomas Zimmermann |
ebf85e |
int i, ret = true;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
- /* Would be simpler to allocate both in one go ? */
|
|
Thomas Zimmermann |
ebf85e |
+ /* Would be simpler to allocate both in one go ? */
|
|
Thomas Zimmermann |
ebf85e |
buf = kzalloc(args_len * 2 + 2, GFP_KERNEL);
|
|
Thomas Zimmermann |
ebf85e |
if (!buf)
|
|
Thomas Zimmermann |
ebf85e |
return false;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
|
|
Thomas Zimmermann |
ebf85e |
if (!msgs) {
|
|
Thomas Zimmermann |
ebf85e |
- kfree(buf);
|
|
Thomas Zimmermann |
ebf85e |
+ kfree(buf);
|
|
Thomas Zimmermann |
ebf85e |
return false;
|
|
Thomas Zimmermann |
ebf85e |
- }
|
|
Thomas Zimmermann |
ebf85e |
+ }
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
@@ -498,7 +499,10 @@ static bool intel_sdvo_write_cmd(struct
|
|
Thomas Zimmermann |
ebf85e |
msgs[i+2].len = 1;
|
|
Thomas Zimmermann |
ebf85e |
msgs[i+2].buf = &status;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
- ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
|
|
Thomas Zimmermann |
ebf85e |
+ if (unlocked)
|
|
Thomas Zimmermann |
ebf85e |
+ ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
|
|
Thomas Zimmermann |
ebf85e |
+ else
|
|
Thomas Zimmermann |
ebf85e |
+ ret = __i2c_transfer(intel_sdvo->i2c, msgs, i+3);
|
|
Thomas Zimmermann |
ebf85e |
if (ret < 0) {
|
|
Thomas Zimmermann |
ebf85e |
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
|
|
Thomas Zimmermann |
ebf85e |
ret = false;
|
|
Thomas Zimmermann |
ebf85e |
@@ -516,6 +520,12 @@ out:
|
|
Thomas Zimmermann |
ebf85e |
return ret;
|
|
Thomas Zimmermann |
ebf85e |
}
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
|
|
Thomas Zimmermann |
ebf85e |
+ const void *args, int args_len)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ return __intel_sdvo_write_cmd(intel_sdvo, cmd, args, args_len, true);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
|
|
Thomas Zimmermann |
ebf85e |
void *response, int response_len)
|
|
Thomas Zimmermann |
ebf85e |
{
|
|
Thomas Zimmermann |
ebf85e |
@@ -602,13 +612,13 @@ static int intel_sdvo_get_pixel_multipli
|
|
Thomas Zimmermann |
ebf85e |
return 4;
|
|
Thomas Zimmermann |
ebf85e |
}
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
-static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
|
|
Thomas Zimmermann |
ebf85e |
- u8 ddc_bus)
|
|
Thomas Zimmermann |
ebf85e |
+static bool __intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
|
|
Thomas Zimmermann |
ebf85e |
+ u8 ddc_bus)
|
|
Thomas Zimmermann |
ebf85e |
{
|
|
Thomas Zimmermann |
ebf85e |
/* This must be the immediately preceding write before the i2c xfer */
|
|
Thomas Zimmermann |
ebf85e |
- return intel_sdvo_write_cmd(intel_sdvo,
|
|
Thomas Zimmermann |
ebf85e |
- SDVO_CMD_SET_CONTROL_BUS_SWITCH,
|
|
Thomas Zimmermann |
ebf85e |
- &ddc_bus, 1);
|
|
Thomas Zimmermann |
ebf85e |
+ return __intel_sdvo_write_cmd(intel_sdvo,
|
|
Thomas Zimmermann |
ebf85e |
+ SDVO_CMD_SET_CONTROL_BUS_SWITCH,
|
|
Thomas Zimmermann |
ebf85e |
+ &ddc_bus, 1, false);
|
|
Thomas Zimmermann |
ebf85e |
}
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
|
|
Thomas Zimmermann |
ebf85e |
@@ -2926,7 +2936,7 @@ static int intel_sdvo_ddc_proxy_xfer(str
|
|
Thomas Zimmermann |
ebf85e |
{
|
|
Thomas Zimmermann |
ebf85e |
struct intel_sdvo *sdvo = adapter->algo_data;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
- if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
|
|
Thomas Zimmermann |
ebf85e |
+ if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
|
|
Thomas Zimmermann |
ebf85e |
return -EIO;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
|
|
Thomas Zimmermann |
ebf85e |
@@ -2943,6 +2953,33 @@ static const struct i2c_algorithm intel_
|
|
Thomas Zimmermann |
ebf85e |
.functionality = intel_sdvo_ddc_proxy_func
|
|
Thomas Zimmermann |
ebf85e |
};
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
+static void proxy_lock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_sdvo *sdvo = adapter->algo_data;
|
|
Thomas Zimmermann |
ebf85e |
+ sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+static int proxy_trylock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_sdvo *sdvo = adapter->algo_data;
|
|
Thomas Zimmermann |
ebf85e |
+ return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+static void proxy_unlock_bus(struct i2c_adapter *adapter,
|
|
Thomas Zimmermann |
ebf85e |
+ unsigned int flags)
|
|
Thomas Zimmermann |
ebf85e |
+{
|
|
Thomas Zimmermann |
ebf85e |
+ struct intel_sdvo *sdvo = adapter->algo_data;
|
|
Thomas Zimmermann |
ebf85e |
+ sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags);
|
|
Thomas Zimmermann |
ebf85e |
+}
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
+const struct i2c_lock_operations proxy_lock_ops = {
|
|
Thomas Zimmermann |
ebf85e |
+ .lock_bus = proxy_lock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+ .trylock_bus = proxy_trylock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+ .unlock_bus = proxy_unlock_bus,
|
|
Thomas Zimmermann |
ebf85e |
+};
|
|
Thomas Zimmermann |
ebf85e |
+
|
|
Thomas Zimmermann |
ebf85e |
static bool
|
|
Thomas Zimmermann |
ebf85e |
intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
|
|
Thomas Zimmermann |
ebf85e |
struct drm_i915_private *dev_priv)
|
|
Thomas Zimmermann |
ebf85e |
@@ -2955,6 +2992,7 @@ intel_sdvo_init_ddc_proxy(struct intel_s
|
|
Thomas Zimmermann |
ebf85e |
sdvo->ddc.dev.parent = &pdev->dev;
|
|
Thomas Zimmermann |
ebf85e |
sdvo->ddc.algo_data = sdvo;
|
|
Thomas Zimmermann |
ebf85e |
sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
|
|
Thomas Zimmermann |
ebf85e |
+ sdvo->ddc.lock_ops = &proxy_lock_ops;
|
|
Thomas Zimmermann |
ebf85e |
|
|
Thomas Zimmermann |
ebf85e |
return i2c_add_adapter(&sdvo->ddc) == 0;
|
|
Thomas Zimmermann |
ebf85e |
}
|