* [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support
2015-08-14 16:50 [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Lukas Wunner
@ 2015-08-14 16:18 ` Lukas Wunner
2015-08-14 16:28 ` [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID Lukas Wunner
2015-08-25 8:13 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Daniel Vetter
2015-08-17 10:36 ` [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Thierry Reding
2015-08-25 8:12 ` Daniel Vetter
2 siblings, 2 replies; 13+ messages in thread
From: Lukas Wunner @ 2015-08-14 16:18 UTC (permalink / raw)
To: dri-devel; +Cc: Daniel Vetter, Dave Airlie, Seth Forshee
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
The gmux allows muxing the DDC independently from the display, so
support this functionality. This will allow reading the EDID for the
inactive GPU, fixing issues with machines that either don't have a VBT
or have invalid mode data in the VBT.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-03-27:
If the inactive client registers before the active client then
old_ddc_owner cannot be determined with find_active_client()
(null pointer dereference). Therefore change semantics of the
->switch_ddc handler callback to return old_ddc_owner.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia 9400M + 9600M GT pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
Cc: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
drivers/platform/x86/apple-gmux.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 0dec3f5..08bdf1e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -273,14 +273,34 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
};
+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+ enum vga_switcheroo_client_id old_ddc_owner;
+
+ if (gmux_read8(apple_gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
+ old_ddc_owner = VGA_SWITCHEROO_IGD;
+ else
+ old_ddc_owner = VGA_SWITCHEROO_DIS;
+
+ pr_debug("Switching gmux DDC from %d to %d\n", old_ddc_owner, id);
+
+ if (id == old_ddc_owner)
+ return old_ddc_owner;
+
+ if (id == VGA_SWITCHEROO_IGD)
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+ else
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+
+ return old_ddc_owner;
+}
+
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD) {
- gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
- gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -347,6 +367,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
}
static struct vga_switcheroo_handler gmux_handler = {
+ .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
--
2.1.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-14 16:18 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Lukas Wunner
@ 2015-08-14 16:28 ` Lukas Wunner
2015-08-17 10:41 ` Thierry Reding
2015-08-18 7:02 ` Jani Nikula
2015-08-25 8:13 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Daniel Vetter
1 sibling, 2 replies; 13+ messages in thread
From: Lukas Wunner @ 2015-08-14 16:28 UTC (permalink / raw)
To: dri-devel; +Cc: Daniel Vetter, Dave Airlie, Seth Forshee
Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
Some dual graphics machines support muxing the DDC separately from the
display, so make use of this functionality when reading the EDID on the
inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
on the DDC mux state.
Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
I can't figure out why I didn't like this, but I rewrote this [...] to
lock/unlock the ddc lines [...]. I think I'd prefer something like that
otherwise the interface got really ugly.
Modified by Lukas Wunner <lukas@wunner.de>, 2015-03-27:
Unlock DDC lines if drm_probe_ddc() fails.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia 9400M + 9600M GT pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dave Airlie <airlied@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
drivers/gpu/drm/drm_edid.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index e6e05bb..cdb2fa1 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -32,6 +32,7 @@
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/vga_switcheroo.h>
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include <drm/drm_displayid.h>
@@ -1377,13 +1378,21 @@ struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
struct edid *edid;
+ struct pci_dev *pdev = connector->dev->pdev;
- if (!drm_probe_ddc(adapter))
+ vga_switcheroo_lock_ddc(pdev);
+
+ if (!drm_probe_ddc(adapter)) {
+ vga_switcheroo_unlock_ddc(pdev);
return NULL;
+ }
edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
if (edid)
drm_get_displayid(connector, edid);
+
+ vga_switcheroo_unlock_ddc(pdev);
+
return edid;
}
EXPORT_SYMBOL(drm_get_edid);
--
2.1.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-14 16:28 ` [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID Lukas Wunner
@ 2015-08-17 10:41 ` Thierry Reding
2015-08-17 20:24 ` Lukas Wunner
2015-08-18 7:02 ` Jani Nikula
1 sibling, 1 reply; 13+ messages in thread
From: Thierry Reding @ 2015-08-17 10:41 UTC (permalink / raw)
To: Lukas Wunner; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
[-- Attachment #1.1: Type: text/plain, Size: 3080 bytes --]
On Fri, Aug 14, 2015 at 06:28:35PM +0200, Lukas Wunner wrote:
> Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> Some dual graphics machines support muxing the DDC separately from the
> display, so make use of this functionality when reading the EDID on the
> inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
> on the DDC mux state.
>
> Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
> I can't figure out why I didn't like this, but I rewrote this [...] to
> lock/unlock the ddc lines [...]. I think I'd prefer something like that
> otherwise the interface got really ugly.
>
> Modified by Lukas Wunner <lukas@wunner.de>, 2015-03-27:
> Unlock DDC lines if drm_probe_ddc() fails.
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
> Tested-by: Pierre Moreau <pierre.morrow@free.fr>
> [MBP 5,3 2009 nvidia 9400M + 9600M GT pre-retina]
> Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
> [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
> Tested-by: William Brown <william@blackhats.net.au>
> [MBP 8,2 2011 intel SNB + amd turks pre-retina]
> Tested-by: Lukas Wunner <lukas@wunner.de>
> [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
> Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
> [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Cc: Dave Airlie <airlied@gmail.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
> drivers/gpu/drm/drm_edid.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index e6e05bb..cdb2fa1 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -32,6 +32,7 @@
> #include <linux/hdmi.h>
> #include <linux/i2c.h>
> #include <linux/module.h>
> +#include <linux/vga_switcheroo.h>
> #include <drm/drmP.h>
> #include <drm/drm_edid.h>
> #include <drm/drm_displayid.h>
> @@ -1377,13 +1378,21 @@ struct edid *drm_get_edid(struct drm_connector *connector,
> struct i2c_adapter *adapter)
> {
> struct edid *edid;
> + struct pci_dev *pdev = connector->dev->pdev;
>
> - if (!drm_probe_ddc(adapter))
> + vga_switcheroo_lock_ddc(pdev);
> +
> + if (!drm_probe_ddc(adapter)) {
> + vga_switcheroo_unlock_ddc(pdev);
> return NULL;
> + }
>
> edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
> if (edid)
> drm_get_displayid(connector, edid);
> +
> + vga_switcheroo_unlock_ddc(pdev);
> +
> return edid;
> }
> EXPORT_SYMBOL(drm_get_edid);
I think this is backwards and it'd be more explicit (though I suspect
slightly more work for this patch) to add a separate helper that does
the VGA switcheroo wrapping rather than have this in drm_get_edid()
where essentially every driver will go through the motions even if it
doesn't remotely support switcheroo.
Thierry
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 159 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-17 10:41 ` Thierry Reding
@ 2015-08-17 20:24 ` Lukas Wunner
2015-08-25 8:00 ` Daniel Vetter
0 siblings, 1 reply; 13+ messages in thread
From: Lukas Wunner @ 2015-08-17 20:24 UTC (permalink / raw)
To: Thierry Reding; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
Hi Thierry,
On Mon, Aug 17, 2015 at 12:41:32PM +0200, Thierry Reding wrote:
> On Fri, Aug 14, 2015 at 06:28:35PM +0200, Lukas Wunner wrote:
> > @@ -1377,13 +1378,21 @@ struct edid *drm_get_edid(struct drm_connector *connector,
> > struct i2c_adapter *adapter)
> > {
> > struct edid *edid;
> > + struct pci_dev *pdev = connector->dev->pdev;
> >
> > - if (!drm_probe_ddc(adapter))
> > + vga_switcheroo_lock_ddc(pdev);
> > +
> > + if (!drm_probe_ddc(adapter)) {
> > + vga_switcheroo_unlock_ddc(pdev);
> > return NULL;
> > + }
> >
> > edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
> > if (edid)
> > drm_get_displayid(connector, edid);
> > +
> > + vga_switcheroo_unlock_ddc(pdev);
> > +
> > return edid;
> > }
> > EXPORT_SYMBOL(drm_get_edid);
>
> I think this is backwards and it'd be more explicit (though I suspect
> slightly more work for this patch) to add a separate helper that does
> the VGA switcheroo wrapping rather than have this in drm_get_edid()
> where essentially every driver will go through the motions even if it
> doesn't remotely support switcheroo.
This is also something I carried over from Seth Forshee's and
Dave Airlie's patches and I think their intention was precisely
to do this in a centralized way in one of the generic functions,
rather than having to modify each driver.
For drivers without vga_switcheroo support, the additional cost
amounts to one mutex_lock/unlock (because there's no handler
registered and vga_switcheroo_lock_ddc bails out immediately
if there's none).
As an example why I think this approach was taken: Let's say that
Tegra or other mobile SoCs have dual GPUs in the future, kind of
like ARM big.LITTLE for graphics. We would potentially support
those devices out of the box without having to modify the driver
to call drm_get_edid_switcheroo() rather than drm_get_edid().
That was kind of the idea I guess.
On the other hand, a case could be made for your suggested approach
as well: The proxying stuff will clutter drm_get_edid() and
drm_dp_dpcd_read() with even more vga_switcheroo calls,
as can be seen in experimental patch 20:
http://lists.freedesktop.org/archives/dri-devel/2015-August/088154.html
Also, to constrain proxying to eDP, I had to amend drm_dp_aux with
a connector attribute so that the connector type can be checked in
drm_dp_dpcd_read() (patch 19):
http://lists.freedesktop.org/archives/dri-devel/2015-August/088172.html
With your approach, I think this will be unnecessary because the
functions in the drivers which would call drm_get_edid_switcheroo()
would already know the connector type.
So once again, a case can be made for either approach, I feel like
I'm not in a position to properly judge this, and I kindly ask that
you or another maintainer make that decision based on the additional
information I've provided above. I'll then gladly adjust the patch.
Thanks,
Lukas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-17 20:24 ` Lukas Wunner
@ 2015-08-25 8:00 ` Daniel Vetter
0 siblings, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2015-08-25 8:00 UTC (permalink / raw)
To: Lukas Wunner; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
On Mon, Aug 17, 2015 at 10:24:32PM +0200, Lukas Wunner wrote:
> Hi Thierry,
>
> On Mon, Aug 17, 2015 at 12:41:32PM +0200, Thierry Reding wrote:
> > On Fri, Aug 14, 2015 at 06:28:35PM +0200, Lukas Wunner wrote:
> > > @@ -1377,13 +1378,21 @@ struct edid *drm_get_edid(struct drm_connector *connector,
> > > struct i2c_adapter *adapter)
> > > {
> > > struct edid *edid;
> > > + struct pci_dev *pdev = connector->dev->pdev;
> > >
> > > - if (!drm_probe_ddc(adapter))
> > > + vga_switcheroo_lock_ddc(pdev);
> > > +
> > > + if (!drm_probe_ddc(adapter)) {
> > > + vga_switcheroo_unlock_ddc(pdev);
> > > return NULL;
> > > + }
> > >
> > > edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
> > > if (edid)
> > > drm_get_displayid(connector, edid);
> > > +
> > > + vga_switcheroo_unlock_ddc(pdev);
> > > +
> > > return edid;
> > > }
> > > EXPORT_SYMBOL(drm_get_edid);
> >
> > I think this is backwards and it'd be more explicit (though I suspect
> > slightly more work for this patch) to add a separate helper that does
> > the VGA switcheroo wrapping rather than have this in drm_get_edid()
> > where essentially every driver will go through the motions even if it
> > doesn't remotely support switcheroo.
>
> This is also something I carried over from Seth Forshee's and
> Dave Airlie's patches and I think their intention was precisely
> to do this in a centralized way in one of the generic functions,
> rather than having to modify each driver.
>
> For drivers without vga_switcheroo support, the additional cost
> amounts to one mutex_lock/unlock (because there's no handler
> registered and vga_switcheroo_lock_ddc bails out immediately
> if there's none).
>
> As an example why I think this approach was taken: Let's say that
> Tegra or other mobile SoCs have dual GPUs in the future, kind of
> like ARM big.LITTLE for graphics. We would potentially support
> those devices out of the box without having to modify the driver
> to call drm_get_edid_switcheroo() rather than drm_get_edid().
> That was kind of the idea I guess.
>
> On the other hand, a case could be made for your suggested approach
> as well: The proxying stuff will clutter drm_get_edid() and
> drm_dp_dpcd_read() with even more vga_switcheroo calls,
> as can be seen in experimental patch 20:
> http://lists.freedesktop.org/archives/dri-devel/2015-August/088154.html
>
> Also, to constrain proxying to eDP, I had to amend drm_dp_aux with
> a connector attribute so that the connector type can be checked in
> drm_dp_dpcd_read() (patch 19):
> http://lists.freedesktop.org/archives/dri-devel/2015-August/088172.html
>
> With your approach, I think this will be unnecessary because the
> functions in the drivers which would call drm_get_edid_switcheroo()
> would already know the connector type.
>
> So once again, a case can be made for either approach, I feel like
> I'm not in a position to properly judge this, and I kindly ask that
> you or another maintainer make that decision based on the additional
> information I've provided above. I'll then gladly adjust the patch.
Generally we make helpers opt-in and not opt-out since there's always the
oddball one out there which needs some additional code. The addition of
drm_do_get_edid is imo clear precedence that there's lots of fun things
going on when fetching edid. Hence I'm also voting for a separate helper
to do ddc switching.
That will also clear up the confusion with drm_dp_aux, adding a
drm_connector there feels wrong since not every dp_aux line has a
connector (e.g. for dp mst). If we can lift this relation out into drivers
(where this is known) that seems cleaner.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-14 16:28 ` [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID Lukas Wunner
2015-08-17 10:41 ` Thierry Reding
@ 2015-08-18 7:02 ` Jani Nikula
2015-08-18 14:16 ` Lukas Wunner
1 sibling, 1 reply; 13+ messages in thread
From: Jani Nikula @ 2015-08-18 7:02 UTC (permalink / raw)
To: Lukas Wunner, dri-devel; +Cc: Daniel Vetter, Seth Forshee, Dave Airlie
On Fri, 14 Aug 2015, Lukas Wunner <lukas@wunner.de> wrote:
> Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> Some dual graphics machines support muxing the DDC separately from the
> display, so make use of this functionality when reading the EDID on the
> inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
> on the DDC mux state.
At a glance, all the referenced bugs have LVDS displays. Is this
supposed to work for eDP as well? How about muxing and locking of DPCD
access?
BR,
Jani.
>
> Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
> I can't figure out why I didn't like this, but I rewrote this [...] to
> lock/unlock the ddc lines [...]. I think I'd prefer something like that
> otherwise the interface got really ugly.
>
> Modified by Lukas Wunner <lukas@wunner.de>, 2015-03-27:
> Unlock DDC lines if drm_probe_ddc() fails.
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
> Tested-by: Pierre Moreau <pierre.morrow@free.fr>
> [MBP 5,3 2009 nvidia 9400M + 9600M GT pre-retina]
> Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
> [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
> Tested-by: William Brown <william@blackhats.net.au>
> [MBP 8,2 2011 intel SNB + amd turks pre-retina]
> Tested-by: Lukas Wunner <lukas@wunner.de>
> [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
> Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
> [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Cc: Dave Airlie <airlied@gmail.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
> drivers/gpu/drm/drm_edid.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index e6e05bb..cdb2fa1 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -32,6 +32,7 @@
> #include <linux/hdmi.h>
> #include <linux/i2c.h>
> #include <linux/module.h>
> +#include <linux/vga_switcheroo.h>
> #include <drm/drmP.h>
> #include <drm/drm_edid.h>
> #include <drm/drm_displayid.h>
> @@ -1377,13 +1378,21 @@ struct edid *drm_get_edid(struct drm_connector *connector,
> struct i2c_adapter *adapter)
> {
> struct edid *edid;
> + struct pci_dev *pdev = connector->dev->pdev;
>
> - if (!drm_probe_ddc(adapter))
> + vga_switcheroo_lock_ddc(pdev);
> +
> + if (!drm_probe_ddc(adapter)) {
> + vga_switcheroo_unlock_ddc(pdev);
> return NULL;
> + }
>
> edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
> if (edid)
> drm_get_displayid(connector, edid);
> +
> + vga_switcheroo_unlock_ddc(pdev);
> +
> return edid;
> }
> EXPORT_SYMBOL(drm_get_edid);
> --
> 2.1.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID
2015-08-18 7:02 ` Jani Nikula
@ 2015-08-18 14:16 ` Lukas Wunner
0 siblings, 0 replies; 13+ messages in thread
From: Lukas Wunner @ 2015-08-18 14:16 UTC (permalink / raw)
To: Jani Nikula; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
Hi Jani,
On Tue, Aug 18, 2015 at 10:02:43AM +0300, Jani Nikula wrote:
> On Fri, 14 Aug 2015, Lukas Wunner <lukas@wunner.de> wrote:
> > Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> > Some dual graphics machines support muxing the DDC separately from the
> > display, so make use of this functionality when reading the EDID on the
> > inactive GPU. Also serialize drm_get_edid() with a mutex to avoid races
> > on the DDC mux state.
>
> At a glance, all the referenced bugs have LVDS displays.
For the original reporters of the bugs that's true, but another user
jumped on the bandwagon who has a retina and that one uses eDP:
https://bugzilla.kernel.org/show_bug.cgi?id=88861#c7
The pre-retinas with dual GPUs (produced 2008-2013) used LVDS.
The retinas (2012-present) use eDP. (Because the dotclock required
for 2880x1800 (337750 kHz) is not supported by LVDS even with dual
channels, max is 224 MHz.)
> Is this supposed to work for eDP as well?
The 3 patches I've posted with v2.1 enable GPU switching only on LVDS,
and only under certain circumstances. (apple-gmux must register before
the inactive GPU's driver and the inactive GPU may not be an Nvidia.)
The 22 patches I've posted with v2 enable GPU switching on LVDS under
any circumstances and also contain experimental commits that preview
how we're tackling eDP support.
> How about muxing and locking of DPCD access?
Muxing the AUX channel separately from the main link is apparently
unsupported by the gmux controller. See the cover letter of v2 for
details (scroll down to "The long journey towards retina support"):
http://lists.freedesktop.org/archives/dri-devel/2015-August/088156.html
I'm trying to solve this by emulating muxing in software: Read access
to the DPCD is proxied via the active GPU. However the drivers also
try to write to the DPCD and abort link training if the write fails,
so in those situations I check if the contents of DPCD match with
what the driver wants to write, and if so, signal success without
writing anything. E.g. nouveau tries to configure 4 lanes at 270000
and i915 configures the same, so no point in writing to DPCD.
Daniel expressed concerns that the inactive GPU might actually write
to DPCD but there's no code let it do that (deliberately so as it
would be unsafe):
http://lists.freedesktop.org/archives/dri-devel/2015-August/088154.html
http://lists.freedesktop.org/archives/dri-devel/2015-July/088173.html
Best regards,
Lukas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support
2015-08-14 16:18 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Lukas Wunner
2015-08-14 16:28 ` [PATCH v2.1 3/3] drm/edid: Switch DDC when reading the EDID Lukas Wunner
@ 2015-08-25 8:13 ` Daniel Vetter
1 sibling, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2015-08-25 8:13 UTC (permalink / raw)
To: Lukas Wunner; +Cc: Daniel Vetter, Dave Airlie, dri-devel, Seth Forshee
On Fri, Aug 14, 2015 at 06:18:55PM +0200, Lukas Wunner wrote:
> Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> The gmux allows muxing the DDC independently from the display, so
> support this functionality. This will allow reading the EDID for the
> inactive GPU, fixing issues with machines that either don't have a VBT
> or have invalid mode data in the VBT.
>
> Modified by Lukas Wunner <lukas@wunner.de>, 2015-03-27:
> If the inactive client registers before the active client then
> old_ddc_owner cannot be determined with find_active_client()
> (null pointer dereference). Therefore change semantics of the
> ->switch_ddc handler callback to return old_ddc_owner.
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
> Tested-by: Pierre Moreau <pierre.morrow@free.fr>
> [MBP 5,3 2009 nvidia 9400M + 9600M GT pre-retina]
> Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
> [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
> Tested-by: William Brown <william@blackhats.net.au>
> [MBP 8,2 2011 intel SNB + amd turks pre-retina]
> Tested-by: Lukas Wunner <lukas@wunner.de>
> [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
> Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
> [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
> drivers/platform/x86/apple-gmux.c | 25 +++++++++++++++++++++++--
> 1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
> index 0dec3f5..08bdf1e 100644
> --- a/drivers/platform/x86/apple-gmux.c
> +++ b/drivers/platform/x86/apple-gmux.c
> @@ -273,14 +273,34 @@ static const struct backlight_ops gmux_bl_ops = {
> .update_status = gmux_update_status,
> };
>
> +static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
> +{
> + enum vga_switcheroo_client_id old_ddc_owner;
> +
> + if (gmux_read8(apple_gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
> + old_ddc_owner = VGA_SWITCHEROO_IGD;
> + else
> + old_ddc_owner = VGA_SWITCHEROO_DIS;
> +
> + pr_debug("Switching gmux DDC from %d to %d\n", old_ddc_owner, id);
> +
> + if (id == old_ddc_owner)
> + return old_ddc_owner;
> +
> + if (id == VGA_SWITCHEROO_IGD)
> + gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
> + else
> + gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
> +
> + return old_ddc_owner;
> +}
> +
> static int gmux_switchto(enum vga_switcheroo_client_id id)
> {
> if (id == VGA_SWITCHEROO_IGD) {
> - gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
> gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
> gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
> } else {
> - gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
> gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
> gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
> }
> @@ -347,6 +367,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
> }
If we'd required that switchto also switches ddc then the error handling
in patch 1 would be a lot simpler. switch_ddc would then only be for
temporary switching while probing.
-Daniel
>
> static struct vga_switcheroo_handler gmux_handler = {
> + .switch_ddc = gmux_switch_ddc,
> .switchto = gmux_switchto,
> .power_state = gmux_set_power_state,
> .get_client_id = gmux_get_client_id,
> --
> 2.1.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC
2015-08-14 16:50 [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Lukas Wunner
2015-08-14 16:18 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Lukas Wunner
@ 2015-08-17 10:36 ` Thierry Reding
2015-08-17 19:11 ` Lukas Wunner
2015-08-25 8:12 ` Daniel Vetter
2 siblings, 1 reply; 13+ messages in thread
From: Thierry Reding @ 2015-08-17 10:36 UTC (permalink / raw)
To: Lukas Wunner; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
[-- Attachment #1.1: Type: text/plain, Size: 7643 bytes --]
On Fri, Aug 14, 2015 at 06:50:15PM +0200, Lukas Wunner wrote:
> Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> During graphics driver initialization it's useful to be able to mux only
> the DDC to the inactive client in order to read the EDID. Add a
> switch_ddc callback to allow capable handlers to provide this
> functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
> only the DDC.
>
> Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
> I can't figure out why I didn't like this, but I rewrote this [...] to
> lock/unlock the ddc lines [...]. I think I'd prefer something like that
> otherwise the interface got really ugly.
>
> Modified by Lukas Wunner <lukas@wunner.de>, 2015-08-14:
> Don't grab vgasr_mutex in lock_ddc/unlock_ddc to avoid the following
> deadlock scenarios: (a) During switch (with vgasr_mutex already held),
> GPU is woken and probes its outputs, tries to re-acquire vgasr_mutex
> to lock DDC lines. (b) Likewise during switch, GPU is suspended and
> calls cancel_delayed_work_sync to stop output polling, if poll task
> is running at this moment we may wait forever for it to finish.
> If we don't grab vgasr_mutex the only bad thing that can happen is
> that the handler suddenly disappears. So block handler deregistration
> until DDC lines are unlocked again.
>
> WARN_ON_ONCE if unlock_ddc is called without calling lock_ddc first.
> Lock ddc_lock in stage2 to avoid race condition where reading the
> EDID and switching happens simultaneously. Switch DDC lines on
> MIGD / MDIS commands and on runtime suspend. Fix bug in stage2
> where no client had the active attribute set if switching failed.
> Fix erroneous interface documentation.
>
> If the inactive client registers before the active client then
> old_ddc_owner cannot be determined with find_active_client()
> (null pointer dereference). Therefore change semantics of the
> ->switch_ddc handler callback to return old_ddc_owner.
>
> v2.1: Overhaul locking, squash commits (requested by Daniel Vetter)
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
> Tested-by: Lukas Wunner <lukas@wunner.de>
> [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Cc: Dave Airlie <airlied@gmail.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
> drivers/gpu/vga/vga_switcheroo.c | 73 +++++++++++++++++++++++++++++++++++++---
> include/linux/vga_switcheroo.h | 6 ++++
> 2 files changed, 74 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
> index 37ac7b5..ac4ac12 100644
> --- a/drivers/gpu/vga/vga_switcheroo.c
> +++ b/drivers/gpu/vga/vga_switcheroo.c
> @@ -9,12 +9,13 @@
>
> Switcher interface - methods require for ATPX and DCM
> - switchto - this throws the output MUX switch
> - - discrete_set_power - sets the power state for the discrete card
> + - switch_ddc - switch only DDC lines, return old DDC owner
> + - power_state - sets the power state for either GPU
>
> GPU driver interface
> - set_gpu_state - this should do the equiv of s/r for the card
> - this should *not* set the discrete power state
> - - switch_check - check if the device is in a position to switch now
> + - can_switch - check if the device is in a position to switch now
> */
>
> #include <linux/module.h>
> @@ -57,6 +58,8 @@ struct vgasr_priv {
> struct list_head clients;
>
> struct vga_switcheroo_handler *handler;
> + struct mutex ddc_lock;
> + int old_ddc_owner;
> };
>
> #define ID_BIT_AUDIO 0x100
> @@ -70,6 +73,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
> /* only one switcheroo per system */
> static struct vgasr_priv vgasr_priv = {
> .clients = LIST_HEAD_INIT(vgasr_priv.clients),
> + .ddc_lock = __MUTEX_INITIALIZER(vgasr_priv.ddc_lock),
> };
>
> static bool vga_switcheroo_ready(void)
> @@ -122,12 +126,14 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler);
> void vga_switcheroo_unregister_handler(void)
> {
> mutex_lock(&vgasr_mutex);
> + mutex_lock(&vgasr_priv.ddc_lock);
> vgasr_priv.handler = NULL;
> if (vgasr_priv.active) {
> pr_info("vga_switcheroo: disabled\n");
> vga_switcheroo_debugfs_fini(&vgasr_priv);
> vgasr_priv.active = false;
> }
> + mutex_unlock(&vgasr_priv.ddc_lock);
> mutex_unlock(&vgasr_mutex);
> }
> EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
> @@ -256,6 +262,43 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
> }
> EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
>
> +int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
> +{
> + int id;
> +
> + mutex_lock(&vgasr_priv.ddc_lock);
> +
> + if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc)
> + return vgasr_priv.old_ddc_owner = -ENODEV;
I find this very hard to read. Can this be split across two lines?
> +
> + id = vgasr_priv.handler->get_client_id(pdev);
> + return vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id);
This too. I also notice that the only place you call this from doesn't
care about the return value, so why even bother returning one?
> +int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
> +{
> + int ret, id;
> +
> + if (WARN_ON_ONCE(!mutex_is_locked(&vgasr_priv.ddc_lock)))
> + return -EINVAL;
> +
> + if (vgasr_priv.old_ddc_owner < 0) {
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + return -ENODEV;
> + }
> +
> + id = vgasr_priv.handler->get_client_id(pdev);
> + if (vgasr_priv.old_ddc_owner != id)
> + ret = vgasr_priv.handler->switch_ddc(vgasr_priv.old_ddc_owner);
> + else
> + ret = vgasr_priv.old_ddc_owner;
> + mutex_unlock(&vgasr_priv.ddc_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
Same comment about the return value here.
> diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
> index b483abd..62f303f 100644
> --- a/include/linux/vga_switcheroo.h
> +++ b/include/linux/vga_switcheroo.h
> @@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
> };
>
> struct vga_switcheroo_handler {
> + int (*switch_ddc)(enum vga_switcheroo_client_id id);
> int (*switchto)(enum vga_switcheroo_client_id id);
> int (*power_state)(enum vga_switcheroo_client_id id,
> enum vga_switcheroo_state state);
> @@ -54,6 +55,9 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
> void vga_switcheroo_client_fb_set(struct pci_dev *dev,
> struct fb_info *info);
>
> +int vga_switcheroo_lock_ddc(struct pci_dev *pdev);
> +int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
> +
> int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
> void vga_switcheroo_unregister_handler(void);
>
> @@ -72,6 +76,8 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
> static inline int vga_switcheroo_register_client(struct pci_dev *dev,
> const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
> static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
> +static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
> +static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
If you care about the return value you'll want to return 0 here to make
sure kernels without VGA switcheroo support will continue to work
properly.
Thierry
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 159 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC
2015-08-17 10:36 ` [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Thierry Reding
@ 2015-08-17 19:11 ` Lukas Wunner
0 siblings, 0 replies; 13+ messages in thread
From: Lukas Wunner @ 2015-08-17 19:11 UTC (permalink / raw)
To: Thierry Reding; +Cc: Daniel Vetter, Seth Forshee, dri-devel, Dave Airlie
Hi Thierry,
Thanks a lot for your comments!
On Mon, Aug 17, 2015 at 12:36:55PM +0200, Thierry Reding wrote:
> On Fri, Aug 14, 2015 at 06:50:15PM +0200, Lukas Wunner wrote:
> > +int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
> > +{
> > + int id;
> > +
> > + mutex_lock(&vgasr_priv.ddc_lock);
> > +
> > + if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc)
> > + return vgasr_priv.old_ddc_owner = -ENODEV;
>
> I find this very hard to read. Can this be split across two lines?
Ok, will rectify in v2.2.
> > + id = vgasr_priv.handler->get_client_id(pdev);
> > + return vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id);
>
> This too. I also notice that the only place you call this from doesn't
> care about the return value, so why even bother returning one?
I carried this over from Seth Forshee's and Dave Airlie's patches,
I believe the rationale is that the ->switch_ddc handler callback
might return an error and that is customarily passed up to the caller.
While drm_get_edid() does indeed ignore that return value (it will
just try to probe DDC anyway), some future function that invokes
vga_switcheroo_lock_ddc() might want to do something useful with it.
So either way has its merits and tbh I don't feel in a position to
judge what's right or wrong here. I'd be grateful if you or some
other maintainer would decide whether to make the return value
void or not and I'll be happy to change the patch accordingly.
> > +static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
> > +static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
>
> If you care about the return value you'll want to return 0 here to make
> sure kernels without VGA switcheroo support will continue to work
> properly.
Maybe I'm mistaken but I believe -ENODEV is correct. If there's no error
then vga_switcheroo_lock_ddc/unlock_ddc() return the old_ddc_owner which
is numbered from 0. E.g. on the MacBook Pro, 0 is IGD and 1 is DIS.
So returning 0 would mean "okay, successfully switched, was previously
switched to the integrated GPU".
Best regards,
Lukas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC
2015-08-14 16:50 [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Lukas Wunner
2015-08-14 16:18 ` [PATCH v2.1 2/3] apple-gmux: Add switch_ddc support Lukas Wunner
2015-08-17 10:36 ` [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC Thierry Reding
@ 2015-08-25 8:12 ` Daniel Vetter
2015-09-17 15:25 ` vga_switcheroo docs (was: Re: [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC) Lukas Wunner
2 siblings, 1 reply; 13+ messages in thread
From: Daniel Vetter @ 2015-08-25 8:12 UTC (permalink / raw)
To: Lukas Wunner; +Cc: Daniel Vetter, Dave Airlie, dri-devel, Seth Forshee
On Fri, Aug 14, 2015 at 06:50:15PM +0200, Lukas Wunner wrote:
> Originally by Seth Forshee <seth.forshee@canonical.com>, 2012-10-04:
> During graphics driver initialization it's useful to be able to mux only
> the DDC to the inactive client in order to read the EDID. Add a
> switch_ddc callback to allow capable handlers to provide this
> functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
> only the DDC.
>
> Modified by Dave Airlie <airlied@gmail.com>, 2012-12-22:
> I can't figure out why I didn't like this, but I rewrote this [...] to
> lock/unlock the ddc lines [...]. I think I'd prefer something like that
> otherwise the interface got really ugly.
>
> Modified by Lukas Wunner <lukas@wunner.de>, 2015-08-14:
> Don't grab vgasr_mutex in lock_ddc/unlock_ddc to avoid the following
> deadlock scenarios: (a) During switch (with vgasr_mutex already held),
> GPU is woken and probes its outputs, tries to re-acquire vgasr_mutex
> to lock DDC lines. (b) Likewise during switch, GPU is suspended and
> calls cancel_delayed_work_sync to stop output polling, if poll task
> is running at this moment we may wait forever for it to finish.
> If we don't grab vgasr_mutex the only bad thing that can happen is
> that the handler suddenly disappears. So block handler deregistration
> until DDC lines are unlocked again.
>
> WARN_ON_ONCE if unlock_ddc is called without calling lock_ddc first.
> Lock ddc_lock in stage2 to avoid race condition where reading the
> EDID and switching happens simultaneously. Switch DDC lines on
> MIGD / MDIS commands and on runtime suspend. Fix bug in stage2
> where no client had the active attribute set if switching failed.
> Fix erroneous interface documentation.
>
> If the inactive client registers before the active client then
> old_ddc_owner cannot be determined with find_active_client()
> (null pointer dereference). Therefore change semantics of the
> ->switch_ddc handler callback to return old_ddc_owner.
>
> v2.1: Overhaul locking, squash commits (requested by Daniel Vetter)
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
> Tested-by: Lukas Wunner <lukas@wunner.de>
> [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
>
> Cc: Seth Forshee <seth.forshee@canonical.com>
> Cc: Dave Airlie <airlied@gmail.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
> drivers/gpu/vga/vga_switcheroo.c | 73 +++++++++++++++++++++++++++++++++++++---
> include/linux/vga_switcheroo.h | 6 ++++
> 2 files changed, 74 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
> index 37ac7b5..ac4ac12 100644
> --- a/drivers/gpu/vga/vga_switcheroo.c
> +++ b/drivers/gpu/vga/vga_switcheroo.c
> @@ -9,12 +9,13 @@
>
> Switcher interface - methods require for ATPX and DCM
> - switchto - this throws the output MUX switch
> - - discrete_set_power - sets the power state for the discrete card
> + - switch_ddc - switch only DDC lines, return old DDC owner
> + - power_state - sets the power state for either GPU
>
> GPU driver interface
> - set_gpu_state - this should do the equiv of s/r for the card
> - this should *not* set the discrete power state
> - - switch_check - check if the device is in a position to switch now
> + - can_switch - check if the device is in a position to switch now
> */
Since you're just diggin around in switcheroo code it would be awesome to
write proper kerneldoc for all the functions exposed to drivers, move the
above to a proper kerneldoc for the vfunc tables (there's new support for
adding kerneldoc split up per member instead of one big pile squashed at
the top). And then bind it together with the overview sections with DOC
comments in Documentation/DocBook/drm.tmpl.
That would also help reviewing ;-)
>
> #include <linux/module.h>
> @@ -57,6 +58,8 @@ struct vgasr_priv {
> struct list_head clients;
>
> struct vga_switcheroo_handler *handler;
> + struct mutex ddc_lock;
> + int old_ddc_owner;
New locks imo need comments about what exactly they protect.
> };
>
> #define ID_BIT_AUDIO 0x100
> @@ -70,6 +73,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
> /* only one switcheroo per system */
> static struct vgasr_priv vgasr_priv = {
> .clients = LIST_HEAD_INIT(vgasr_priv.clients),
> + .ddc_lock = __MUTEX_INITIALIZER(vgasr_priv.ddc_lock),
> };
>
> static bool vga_switcheroo_ready(void)
> @@ -122,12 +126,14 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler);
> void vga_switcheroo_unregister_handler(void)
> {
> mutex_lock(&vgasr_mutex);
> + mutex_lock(&vgasr_priv.ddc_lock);
> vgasr_priv.handler = NULL;
> if (vgasr_priv.active) {
> pr_info("vga_switcheroo: disabled\n");
> vga_switcheroo_debugfs_fini(&vgasr_priv);
> vgasr_priv.active = false;
> }
> + mutex_unlock(&vgasr_priv.ddc_lock);
> mutex_unlock(&vgasr_mutex);
> }
> EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
> @@ -256,6 +262,43 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
> }
> EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
>
> +int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
Since this can fail please call it something like try_lock_ddc to make
that clear to callers. Or make it return void.
> +{
> + int id;
> +
> + mutex_lock(&vgasr_priv.ddc_lock);
> +
> + if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc)
> + return vgasr_priv.old_ddc_owner = -ENODEV;
> +
> + id = vgasr_priv.handler->get_client_id(pdev);
> + return vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id);
Looking at patch 3 you don't seem to handle this error. Also if this
function fails it should _not_ grab the lock so that we can do something
like
ret = try_lock_ddc();
if (ret) {
printk("arg!");
return ret;
}
drm_get_edid();
unlock_ddc();
}
> +}
> +EXPORT_SYMBOL(vga_switcheroo_lock_ddc);
> +
> +int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
> +{
> + int ret, id;
> +
> + if (WARN_ON_ONCE(!mutex_is_locked(&vgasr_priv.ddc_lock)))
> + return -EINVAL;
> +
> + if (vgasr_priv.old_ddc_owner < 0) {
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + return -ENODEV;
> + }
> +
> + id = vgasr_priv.handler->get_client_id(pdev);
> + if (vgasr_priv.old_ddc_owner != id)
> + ret = vgasr_priv.handler->switch_ddc(vgasr_priv.old_ddc_owner);
> + else
> + ret = vgasr_priv.old_ddc_owner;
> + mutex_unlock(&vgasr_priv.ddc_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
> +
> static int vga_switcheroo_show(struct seq_file *m, void *v)
> {
> struct vga_switcheroo_client *client;
> @@ -341,8 +384,6 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
> if (!active)
> return 0;
>
> - active->active = false;
> -
> set_audio_state(active->id, VGA_SWITCHEROO_OFF);
>
> if (new_client->fb_info) {
> @@ -353,9 +394,21 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
> console_unlock();
> }
>
> + if (vgasr_priv.handler->switch_ddc) {
> + mutex_lock(&vgasr_priv.ddc_lock);
> + vgasr_priv.handler->switch_ddc(new_client->id);
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + }
> ret = vgasr_priv.handler->switchto(new_client->id);
> - if (ret)
> + if (ret) {
> + if (vgasr_priv.handler->switch_ddc) {
> + mutex_lock(&vgasr_priv.ddc_lock);
> + vgasr_priv.handler->switch_ddc(active->id);
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + }
Just for safety I'd grab the ddc_lock around the entire sequence.
Overall there seems to be a lot less scary in these 3 patches than the
previous series. Is this really all due to squashing or is this series
incomplete?
-Daniel
> return ret;
> + }
> + active->active = false;
>
> if (new_client->ops->reprobe)
> new_client->ops->reprobe(new_client->pdev);
> @@ -468,6 +521,11 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
> vgasr_priv.delayed_switch_active = false;
>
> if (just_mux) {
> + if (vgasr_priv.handler->switch_ddc) {
> + mutex_lock(&vgasr_priv.ddc_lock);
> + vgasr_priv.handler->switch_ddc(client_id);
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + }
> ret = vgasr_priv.handler->switchto(client_id);
> goto out;
> }
> @@ -623,6 +681,11 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
> ret = dev->bus->pm->runtime_suspend(dev);
> if (ret)
> return ret;
> + if (vgasr_priv.handler->switch_ddc) {
> + mutex_lock(&vgasr_priv.ddc_lock);
> + vgasr_priv.handler->switch_ddc(VGA_SWITCHEROO_IGD);
> + mutex_unlock(&vgasr_priv.ddc_lock);
> + }
> if (vgasr_priv.handler->switchto)
> vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
> vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
> diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
> index b483abd..62f303f 100644
> --- a/include/linux/vga_switcheroo.h
> +++ b/include/linux/vga_switcheroo.h
> @@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
> };
>
> struct vga_switcheroo_handler {
> + int (*switch_ddc)(enum vga_switcheroo_client_id id);
> int (*switchto)(enum vga_switcheroo_client_id id);
> int (*power_state)(enum vga_switcheroo_client_id id,
> enum vga_switcheroo_state state);
> @@ -54,6 +55,9 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
> void vga_switcheroo_client_fb_set(struct pci_dev *dev,
> struct fb_info *info);
>
> +int vga_switcheroo_lock_ddc(struct pci_dev *pdev);
> +int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
> +
> int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
> void vga_switcheroo_unregister_handler(void);
>
> @@ -72,6 +76,8 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
> static inline int vga_switcheroo_register_client(struct pci_dev *dev,
> const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
> static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
> +static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
> +static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
> static inline int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) { return 0; }
> static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
> const struct vga_switcheroo_client_ops *ops,
> --
> 2.1.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread* vga_switcheroo docs (was: Re: [PATCH v2.1 1/3] vga_switcheroo: Add support for switching only the DDC)
2015-08-25 8:12 ` Daniel Vetter
@ 2015-09-17 15:25 ` Lukas Wunner
0 siblings, 0 replies; 13+ messages in thread
From: Lukas Wunner @ 2015-09-17 15:25 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Dave Airlie, dri-devel
Hi Daniel,
On Tue, Aug 25, 2015 at 10:12:50AM +0200, Daniel Vetter wrote:
> Since you're just diggin around in switcheroo code it would be awesome to
> write proper kerneldoc for all the functions exposed to drivers, move the
> above to a proper kerneldoc for the vfunc tables
Alright, a patch set with vga_switcheroo docs is coming up right after this
e-mail. I also fixed some bugs and cosmetic issues while I was at it.
To ease reviewing I've pushed this to GitHub:
https://github.com/l1k/linux/commits/vga_switcheroo_docs
Patch #2 requires Markdown support so you may want to postpone that single
patch for now. The patches are based on today's topic/drm-misc.
> (there's new support for adding kerneldoc split up per member instead of
> one big pile squashed at the top).
To be honest the data structures aren't that large so I felt that the
traditional "docs above, struct below" way is clearer and more concise
in this case.
> And then bind it together with the overview sections with DOC
> comments in Documentation/DocBook/drm.tmpl.
vga_switcheroo is a subsystem of its own which interfaces not just with
DRM but also with multiplexer drivers, ALSA and power management,
so I put it in a separate .tmpl file.
Thanks,
Lukas
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread