[PATCH 2/2] module: avoid exporting module_mutex

2012-03-10 Thread Cong Wang
Avoid exporting internal locks to modules, export two
functions lock_modules()/unlock_modules() for them instead.

Cc: Rusty Russell 
Signed-off-by: Cong Wang 
---
 drivers/gpu/drm/drm_fb_helper.c |4 ++--
 include/linux/module.h  |3 ++-
 kernel/kprobes.c|4 ++--
 kernel/module.c |   16 ++--
 4 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index aada26f..c184759 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1451,9 +1451,9 @@ static int __init drm_fb_helper_modinit(void)
const char *name = "fbcon";
struct module *fbcon;

-   mutex_lock(_mutex);
+   lock_modules();
fbcon = find_module(name);
-   mutex_unlock(_mutex);
+   unlock_modules();

if (!fbcon)
request_module_nowait(name);
diff --git a/include/linux/module.h b/include/linux/module.h
index 4598bf0..5cf6428 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -374,7 +374,8 @@ struct module
 #define MODULE_ARCH_INIT {}
 #endif

-extern struct mutex module_mutex;
+extern void lock_modules(void);
+extern void unlock_modules(void);

 /* FIXME: It'd be nice to isolate modules during init, too, so they
aren't used before they (may) fail.  But presently too much code
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index c62b854..0670fb1 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -562,7 +562,7 @@ static __kprobes void kprobe_optimizer(struct work_struct 
*work)
LIST_HEAD(free_list);

/* Lock modules while optimizing kprobes */
-   mutex_lock(_mutex);
+   lock_modules();
mutex_lock(_mutex);

/*
@@ -587,7 +587,7 @@ static __kprobes void kprobe_optimizer(struct work_struct 
*work)
do_free_cleaned_kprobes(_list);

mutex_unlock(_mutex);
-   mutex_unlock(_mutex);
+   unlock_modules();

/* Step 5: Kick optimizer again if needed */
if (!list_empty(_list) || !list_empty(_list))
diff --git a/kernel/module.c b/kernel/module.c
index e0b12f7..1165d5d 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -95,8 +95,20 @@
  * 2) module_use links,
  * 3) module_addr_min/module_addr_max.
  * (delete uses stop_machine/add uses RCU list operations). */
-DEFINE_MUTEX(module_mutex);
-EXPORT_SYMBOL_GPL(module_mutex);
+static DEFINE_MUTEX(module_mutex);
+
+void lock_modules(void)
+{
+   mutex_lock(_mutex);
+}
+EXPORT_SYMBOL(lock_modules);
+
+void unlock_modules(void)
+{
+   mutex_unlock(_mutex);
+}
+EXPORT_SYMBOL(unlock_modules);
+
 static LIST_HEAD(modules);
 #ifdef CONFIG_KGDB_KDB
 struct list_head *kdb_modules =  /* kdb needs the list of modules */
-- 
1.7.7.6



[PATCH 3/3] drivers-gpu-drm-i915-invert-backlight-brightness

2012-03-10 Thread Carsten Emde
An embedded and charset-unspecified text was scrubbed...
Name: drivers-gpu-drm-i915-invert-backlight-brightness.patch
URL: 
<http://lists.freedesktop.org/archives/dri-devel/attachments/20120310/8f85f259/attachment.ksh>


[PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch

2012-03-10 Thread Carsten Emde
An embedded and charset-unspecified text was scrubbed...
Name: drivers-gpu-drm-add-disable-enable-connector.patch
URL: 
<http://lists.freedesktop.org/archives/dri-devel/attachments/20120310/92849661/attachment.asc>


[PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch

2012-03-10 Thread Carsten Emde
An embedded and charset-unspecified text was scrubbed...
Name: drivers-gpu-drm-allow-to-load-edid-firmware.patch
URL: 
<http://lists.freedesktop.org/archives/dri-devel/attachments/20120310/2007a8ce/attachment.txt>


[PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware

2012-03-10 Thread Carsten Emde
In the good old days when graphics parameters were configured explicitly
in a file called xorg.conf, even broken hardware could be managed.

Today, with the advent of Kernel Mode Setting, a graphics board is
either correctly working because all components follow the standards -
or the computer is unusable, because the screen remains dark after
booting or displays the wrong area. Cases when this happens are:
- The BIOS assumes that an LVDS is always connected, even if it isn't.
- The graphics board does not recognize the monitor.
- The graphics board is unable to detect any EDID data.
- The graphics board incorrectly forwards EDID data to the driver.
- The monitor sends bogus EDID data.
- A KVM sends its own EDID data instead of querying the connected monitor.
- The brightness setting of the panel backlight does not work.
- Any combination of the above.
Adding the kernel parameter "nomodeset" helps in most cases, but causes
restrictions later on.

The three patches of this series add module parameters to the
drm_kms_helper module that
1. allow to load an EDID data set via the firmware interface,
2. provide a module parameter to selectively enable or disable a
graphics port,
3. provide a module parameter to select inverted brightness.

EDID data sets along with source files are provided for commonly used
screen resolutions (1024x768, 1280x1024, 1680x1050, 1920x1080).

Please note that these patches neither fix a kernel bug nor provide any
extra functionality. They simply work around broken hardware that
otherwise would be either unusable or usable in a very restricted way.
The patches do not modify the current functionality of the related
components in any way, unless the kernel is configured accordingly
and/or the newly provided module parameters are set.

-Carsten. 



[Bug 47162] Screen went black for seconds, 100% cpu usage on dri2Throttle/sched_yield

2012-03-10 Thread bugzilla-dae...@freedesktop.org
https://bugs.freedesktop.org/show_bug.cgi?id=47162

Michel D?nzer  changed:

   What|Removed |Added

 AssignedTo|xorg-driver-ati at lists.x.org |dri-devel at 
lists.freedesktop
   ||.org
  QAContact|xorg-team at lists.x.org   |
Product|xorg|Mesa
Version|7.4 (2008.09)   |8.0
  Component|Driver/Radeon   |Drivers/Gallium/r600

--- Comment #1 from Michel D?nzer  2012-03-10 01:19:06 
PST ---
(In reply to comment #1)
> OpenGL version string: 2.1 Mesa 8.0

The r600g driver from Mesa 8.0.1 or newer should deal with this more
gracefully.

-- 
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
--- You are receiving this mail because: ---
You are the assignee for the bug.


[PATCH 10/10 v2] drm/i915/intel_i2c: enable gmbus interrupts

2012-03-10 Thread Daniel Kurtz
Instead of polling for gmbus state changes, use the corresponding gmbus
interrupts, when possible.

There are still some cases where using the GMBUS interrupts is not
possible.  For instance, this patch only enables the interrupt for
ironlake (+ sandy bridge), and ivybridge.  It does not enable them for the
older i915 path through the driver.  Also, there are cases where a gmbus
transaction may be requested before irqs have even been enabled.

For this reason, the older polling loop is left in place, as a backup.

Also, since the interrupts can be enabled/disabled completely
asynchronously from any active gmbus transactions, changing the interrupt
enable is protected by the gmbus transaction mutex.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/i915_drv.h  |2 +
 drivers/gpu/drm/i915/i915_irq.c  |   22 +-
 drivers/gpu/drm/i915/i915_reg.h  |1 +
 drivers/gpu/drm/i915/intel_drv.h |6 +++
 drivers/gpu/drm/i915/intel_i2c.c |   82 --
 5 files changed, 97 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 68aef65..156ad6d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -302,6 +302,8 @@ typedef struct drm_i915_private {
u32 reg0;
} *gmbus;
struct mutex gmbus_mutex;
+   wait_queue_head_t gmbus_waitq;
+   bool gmbus_irq_enabled;

struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5bd4361..12a2259 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -432,13 +432,23 @@ static void pch_irq_handler(struct drm_device *dev)

pch_iir = I915_READ(SDEIIR);

+   if (HAS_PCH_CPT(dev)) {
+   if (pch_iir & SDE_GMBUS_CPT) {
+   DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+   intel_gmbus_irq(dev);
+   }
+   return;
+   }
+
if (pch_iir & SDE_AUDIO_POWER_MASK)
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
 (pch_iir & SDE_AUDIO_POWER_MASK) >>
 SDE_AUDIO_POWER_SHIFT);

-   if (pch_iir & SDE_GMBUS)
+   if (pch_iir & SDE_GMBUS) {
DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+   intel_gmbus_irq(dev);
+   }

if (pch_iir & SDE_AUDIO_HDCP_MASK)
DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
@@ -1847,13 +1857,15 @@ static int ironlake_irq_postinstall(struct drm_device 
*dev)
hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
SDE_PORTB_HOTPLUG_CPT |
SDE_PORTC_HOTPLUG_CPT |
-   SDE_PORTD_HOTPLUG_CPT);
+   SDE_PORTD_HOTPLUG_CPT |
+   SDE_GMBUS_CPT);
} else {
hotplug_mask = (SDE_CRT_HOTPLUG |
SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG |
SDE_PORTD_HOTPLUG |
-   SDE_AUX_MASK);
+   SDE_AUX_MASK |
+   SDE_GMBUS);
}

dev_priv->pch_irq_mask = ~hotplug_mask;
@@ -1863,6 +1875,7 @@ static int ironlake_irq_postinstall(struct drm_device 
*dev)
I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER);

+   intel_gmbus_irq_enable(dev);
ironlake_enable_pch_hotplug(dev);

if (IS_IRONLAKE_M(dev)) {
@@ -1922,6 +1935,7 @@ static int ivybridge_irq_postinstall(struct drm_device 
*dev)
I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER);

+   intel_gmbus_irq_enable(dev);
ironlake_enable_pch_hotplug(dev);

return 0;
@@ -2049,6 +2063,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(GTIER, 0x0);
I915_WRITE(GTIIR, I915_READ(GTIIR));

+   intel_gmbus_irq_disable(dev);
+
I915_WRITE(SDEIMR, 0x);
I915_WRITE(SDEIER, 0x0);
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 89cace2..94333e8 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3080,6 +3080,7 @@
 #define SDE_TRANSA_FIFO_UNDER  (1 << 0)
 #define SDE_TRANS_MASK (0x3f)
 /* CPT */
+#define SDE_GMBUS_CPT  (1 << 17)
 #define SDE_CRT_HOTPLUG_CPT(1 << 19)
 #define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
 #define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7538f2e..7c91354 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -47,6 +47,8 @@

 #define wait_for(COND, MS) 

[PATCH 09/10 v2] drm/i915/intel_i2c: reuse GMBUS2 value read in polling loop

2012-03-10 Thread Daniel Kurtz
Save the GMBUS2 value read while polling for state changes, and then
reuse this value when determining for which reason the loops were exited.
This is a small optimization which saves a couple of bus accesses for
memory mapped IO registers.

Signed-off-by: Daniel Kurtz 
Reviewed-by: Chris Wilson 
---
 drivers/gpu/drm/i915/intel_i2c.c |   19 ++-
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 61fe317..2c372d3 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -243,6 +243,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
struct drm_i915_private *dev_priv = adapter->algo_data;
int i, reg_offset;
int ret = 0;
+   u32 gmbus2 = 0;

if (bus->force_bit)
return intel_i2c_quirk_xfer(dev_priv,
@@ -296,12 +297,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
do {
u32 val, loop = 0;

-   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 +
+reg_offset)) &
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) &
-   GMBUS_SATOER)
+   if (gmbus2 & GMBUS_SATOER)
goto clear_err;

val = I915_READ(GMBUS3 + reg_offset);
@@ -335,21 +336,21 @@ gmbus_xfer(struct i2c_adapter *adapter,
I915_WRITE(GMBUS3 + reg_offset, val);
POSTING_READ(GMBUS2 + reg_offset);

-   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 +
+reg_offset)) &
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) &
- GMBUS_SATOER)
+   if (gmbus2 & GMBUS_SATOER)
goto clear_err;
}
}

-   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+   if (gmbus2 & GMBUS_SATOER)
goto clear_err;
}

@@ -373,7 +374,7 @@ clear_err:
ret = -ENXIO;

 done:
-   if (I915_READ(GMBUS2 + reg_offset) & GMBUS_HW_WAIT_PHASE) {
+   if (gmbus2 & GMBUS_HW_WAIT_PHASE) {
I915_WRITE(GMBUS1 + reg_offset,
   GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
POSTING_READ(GMBUS2 + reg_offset);
-- 
1.7.7.3



[PATCH 08/10 v2] drm/i915/intel_i2c: use INDEX cycles for i2c read transactions

2012-03-10 Thread Daniel Kurtz
It is very common for an i2c device to require a small 1 or 2 byte write
followed by a read.  For example, when reading from an i2c EEPROM it is
common to write and address, offset or index followed by a reading some
values.

The i915 gmbus controller provides a special "INDEX" cycle for performing
such a small write followed by a read.  The INDEX can be either one or two
bytes long.  The advantage of using such a cycle is that the CPU has
slightly less work to do once the read with INDEX cycle is started.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/intel_i2c.c |   32 ++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index b79a181..61fe317 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -255,12 +255,40 @@ gmbus_xfer(struct i2c_adapter *adapter,
I915_WRITE(GMBUS0 + reg_offset, bus->reg0);

for (i = 0; i < num; i++) {
-   u16 len = msgs[i].len;
-   u8 *buf = msgs[i].buf;
+   u16 len;
+   u8 *buf;
+   u32 gmbus5 = 0;
+   u32 gmbus1_index = 0;
+
+   /*
+* The gmbus controller can combine a 1 or 2 byte write with a
+* read that immediately follows it by using an "INDEX" cycle.
+*/
+   if (i + 1 < num &&
+   !(msgs[i].flags & I2C_M_RD) &&
+   (msgs[i + 1].flags & I2C_M_RD) &&
+   msgs[i].len <= 2) {
+   if (msgs[i].len == 2)
+   gmbus5 = GMBUS_2BYTE_INDEX_EN |
+msgs[i].buf[1] |
+(msgs[i].buf[0] << 8);
+   if (msgs[i].len == 1)
+   gmbus1_index = GMBUS_CYCLE_INDEX |
+  (msgs[i].buf[0] <<
+   GMBUS_SLAVE_INDEX_SHIFT);
+   i += 1;  /* set i to the index of the read xfer */
+   }
+
+   len = msgs[i].len;
+   buf = msgs[i].buf;
+
+   /* GMBUS5 holds 16-bit index, but must be 0 if not used */
+   I915_WRITE(GMBUS5 + reg_offset, gmbus5);

if (msgs[i].flags & I2C_M_RD) {
I915_WRITE(GMBUS1 + reg_offset,
   GMBUS_CYCLE_WAIT |
+  gmbus1_index |
   (len << GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-- 
1.7.7.3



[PATCH 07/10 v2] drm/i915/intel_i2c: use WAIT cycle, not STOP

2012-03-10 Thread Daniel Kurtz
The i915 is only able to generate a STOP cycle (i.e. finalize an i2c
transaction) during a DATA or WAIT phase.  In other words, the
controller rejects a STOP requested as part of the first transaction in a
sequence.

Thus, for the first transaction we must always use a WAIT cycle, detect
when the device has finished (and is in a WAIT phase), and then either
start the next transaction, or, if there are no more transactions,
generate a STOP cycle.

Note: Theoretically, the last transaction of a multi-transaction sequence
could initiate a STOP cycle.  However, this slight optimization is left
for another patch.  We return -ETIMEDOUT if the hardware doesn't
deactivate after the STOP cycle.

This patch also takes advantage (in the write path) of the double-buffered
GMBUS3 data register by writing two 4-byte words before the first wait for
HW_RDY.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/intel_i2c.c |   42 +
 1 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 151b828..b79a181 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -260,7 +260,7 @@ gmbus_xfer(struct i2c_adapter *adapter,

if (msgs[i].flags & I2C_M_RD) {
I915_WRITE(GMBUS1 + reg_offset,
-  GMBUS_CYCLE_WAIT | (i + 1 == num ? 
GMBUS_CYCLE_STOP : 0) |
+  GMBUS_CYCLE_WAIT |
   (len << GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
@@ -272,7 +272,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) & 
GMBUS_SATOER)
+   if (I915_READ(GMBUS2 + reg_offset) &
+   GMBUS_SATOER)
goto clear_err;

val = I915_READ(GMBUS3 + reg_offset);
@@ -291,20 +292,13 @@ gmbus_xfer(struct i2c_adapter *adapter,

I915_WRITE(GMBUS3 + reg_offset, val);
I915_WRITE(GMBUS1 + reg_offset,
-  (i + 1 == num ? GMBUS_CYCLE_STOP : 
GMBUS_CYCLE_WAIT) |
+  GMBUS_CYCLE_WAIT |
   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
POSTING_READ(GMBUS2 + reg_offset);

while (len) {
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
-(GMBUS_SATOER | GMBUS_HW_RDY),
-50))
-   goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) & 
GMBUS_SATOER)
-   goto clear_err;
-
val = loop = 0;
do {
val |= *buf++ << (8 * loop);
@@ -312,11 +306,18 @@ gmbus_xfer(struct i2c_adapter *adapter,

I915_WRITE(GMBUS3 + reg_offset, val);
POSTING_READ(GMBUS2 + reg_offset);
+
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
+   goto timeout;
+   if (I915_READ(GMBUS2 + reg_offset) &
+ GMBUS_SATOER)
+   goto clear_err;
}
}

-   if (i + 1 < num &&
-   wait_for(I915_READ(GMBUS2 + reg_offset) &
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
 50))
goto timeout;
@@ -344,9 +345,22 @@ clear_err:
ret = -ENXIO;

 done:
-   /* Mark the GMBUS interface as disabled. We will re-enable it at the
-* start of the next xfer, till then let it sleep.
+   if (I915_READ(GMBUS2 + reg_offset) & GMBUS_HW_WAIT_PHASE) {
+   I915_WRITE(GMBUS1 + reg_offset,
+  GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+   POSTING_READ(GMBUS2 + reg_offset);
+   }
+
+   /* Mark the GMBUS interface as disabled after 

[PATCH 06/10 v2] drm/i915/intel_i2c: return -ENXIO for device NAK

2012-03-10 Thread Daniel Kurtz
Return -ENXIO if a device NAKs a transaction.

Note: We should return -ETIMEDOUT, too if the transaction times out,
however, that error path is currently handled by the 'bit-bang fallback'.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/intel_i2c.c |   12 +++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 232b7cb..151b828 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -242,6 +242,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
   adapter);
struct drm_i915_private *dev_priv = adapter->algo_data;
int i, reg_offset;
+   int ret = 0;

if (bus->force_bit)
return intel_i2c_quirk_xfer(dev_priv,
@@ -333,6 +334,15 @@ clear_err:
I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
I915_WRITE(GMBUS1 + reg_offset, 0);

+   /*
+* If no ACK is received during the address phase of a transaction,
+* the adapter must report -ENXIO.
+* It is not clear what to return if no ACK is received at other times.
+* So, we always return -ENXIO in all NAK cases, to ensure we send
+* it at least during the one case that is specified.
+*/
+   ret = -ENXIO;
+
 done:
/* Mark the GMBUS interface as disabled. We will re-enable it at the
 * start of the next xfer, till then let it sleep.
@@ -341,7 +351,7 @@ done:

mutex_unlock(_priv->gmbus_mutex);

-   return i;
+   return ret ?: i;

 timeout:
DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d 
[%s]\n",
-- 
1.7.7.3



[PATCH 05/10 v2] drm/i915/intel_i2c: add locking around i2c algorithm accesses

2012-03-10 Thread Daniel Kurtz
The i915 has multiple i2c adapters.  However, they all share a single
single set of i2c control registers (algorithm).  Thus, different threads
trying to access different adapters could interfere with each other.

Note: different threads trying to access the same channel is already
handled in the i2c-core using the i2c adapter lock.

This patch adds a mutex to serialize access to the gmbus_xfer routine.
Note: the same mutex serializes both bit banged and native xfers.

Signed-off-by: Yufeng Shen 
Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/i915_drv.h  |1 +
 drivers/gpu/drm/i915/intel_i2c.c |   13 +
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9a81e48..68aef65 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -301,6 +301,7 @@ typedef struct drm_i915_private {
struct i2c_adapter *force_bit;
u32 reg0;
} *gmbus;
+   struct mutex gmbus_mutex;

struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index f53f525..232b7cb 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -212,6 +212,8 @@ intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
   adapter);
int ret;

+   mutex_lock(_priv->gmbus_mutex);
+
intel_i2c_reset(dev_priv->dev);

intel_i2c_quirk_set(dev_priv, true);
@@ -225,6 +227,8 @@ intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
set_clock(gpio, 1);
intel_i2c_quirk_set(dev_priv, false);

+   mutex_unlock(_priv->gmbus_mutex);
+
return ret;
 }

@@ -243,6 +247,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
return intel_i2c_quirk_xfer(dev_priv,
bus->force_bit, msgs, num);

+   mutex_lock(_priv->gmbus_mutex);
+
reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;

I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
@@ -332,6 +338,9 @@ done:
 * start of the next xfer, till then let it sleep.
 */
I915_WRITE(GMBUS0 + reg_offset, 0);
+
+   mutex_unlock(_priv->gmbus_mutex);
+
return i;

 timeout:
@@ -339,6 +348,8 @@ timeout:
 bus->reg0 & 0xff, bus->adapter.name);
I915_WRITE(GMBUS0 + reg_offset, 0);

+   mutex_unlock(_priv->gmbus_mutex);
+
/* 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)
@@ -381,6 +392,8 @@ int intel_setup_gmbus(struct drm_device *dev)
if (dev_priv->gmbus == NULL)
return -ENOMEM;

+   mutex_init(_priv->gmbus_mutex);
+
for (i = 0; i < ARRAY_SIZE(gmbus_ports); i++) {
struct intel_gmbus *bus = _priv->gmbus[i];
u32 port = i + 1; /* +1 to map gmbus index to pin pair */
-- 
1.7.7.3



[PATCH 04/10 v2] drm/i915/intel_i2c: cleanup gmbus/gpio pin assignments

2012-03-10 Thread Daniel Kurtz
There is no "disabled" port 0.  So, don't even try to initialize/scan
it, etc.  This saves a bit of time when initializing the driver, since
it avoids a 50ms timeout waiting for a device to respond on a port that
doesn't even exist.

Similarly, don't initialize the "reserved" port 7, either.

Tested on Sandybridge (gen 6, PCH == CougarPoint) hardware.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/i915_reg.h  |1 -
 drivers/gpu/drm/i915/intel_i2c.c |   64 +
 2 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 56af0df..89cace2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -699,7 +699,6 @@
 #define   GMBUS_PORT_DPB   5 /* SDVO, HDMIB */
 #define   GMBUS_PORT_DPD   6 /* HDMID */
 #define   GMBUS_PORT_RESERVED  7 /* 7 reserved */
-#define   GMBUS_NUM_PORTS  8
 #define GMBUS1 0x5104 /* command/status */
 #define   GMBUS_SW_CLR_INT (1<<31)
 #define   GMBUS_SW_RDY (1<<30)
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 87a3abf..f53f525 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -35,6 +35,20 @@
 #include "i915_drm.h"
 #include "i915_drv.h"

+struct gmbus_port {
+   const char *name;
+   int reg;
+};
+
+static const struct gmbus_port gmbus_ports[] = {
+   { "ssc", GPIOB },
+   { "vga", GPIOA },
+   { "panel", GPIOC },
+   { "dpc", GPIOD },
+   { "dpb", GPIOE },
+   { "dpd", GPIOF },
+};
+
 /* Intel GPIO access functions */

 #define I2C_RISEFALL_TIME 20
@@ -150,32 +164,22 @@ static void set_data(void *data, int state_high)
 static struct i2c_adapter *
 intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-   static const int map_pin_to_reg[] = {
-   0,
-   GPIOB,
-   GPIOA,
-   GPIOC,
-   GPIOD,
-   GPIOE,
-   GPIOF,
-   0,
-   };
struct intel_gpio *gpio;

-   if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
-   return NULL;
+   pin -= 1;  /* NB: -1 to map pin pair to gmbus array index */
+   BUG_ON(pin >= ARRAY_SIZE(gmbus_ports));

gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
if (gpio == NULL)
return NULL;

-   gpio->reg = map_pin_to_reg[pin];
+   gpio->reg = gmbus_ports[pin].reg;
if (HAS_PCH_SPLIT(dev_priv->dev))
gpio->reg += PCH_GPIOA - GPIOA;
gpio->dev_priv = dev_priv;

snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
-"i915 GPIO%c", "?BACDEF?"[pin]);
+"i915 GPIO%c", "BACDEF"[pin]);
gpio->adapter.owner = THIS_MODULE;
gpio->adapter.algo_data = >algo;
gpio->adapter.dev.parent = _priv->dev->pdev->dev;
@@ -369,33 +373,22 @@ static const struct i2c_algorithm gmbus_algorithm = {
  */
 int intel_setup_gmbus(struct drm_device *dev)
 {
-   static const char *names[GMBUS_NUM_PORTS] = {
-   "disabled",
-   "ssc",
-   "vga",
-   "panel",
-   "dpc",
-   "dpb",
-   "dpd",
-   "reserved",
-   };
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i;

-   dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
- GFP_KERNEL);
+   dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus),
+ ARRAY_SIZE(gmbus_ports), GFP_KERNEL);
if (dev_priv->gmbus == NULL)
return -ENOMEM;

-   for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+   for (i = 0; i < ARRAY_SIZE(gmbus_ports); i++) {
struct intel_gmbus *bus = _priv->gmbus[i];
+   u32 port = i + 1; /* +1 to map gmbus index to pin pair */

bus->adapter.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC;
-   snprintf(bus->adapter.name,
-sizeof(bus->adapter.name),
-"i915 gmbus %s",
-names[i]);
+   snprintf(bus->adapter.name, sizeof(bus->adapter.name),
+"i915 gmbus %s", gmbus_ports[i].name);

bus->adapter.dev.parent = >pdev->dev;
bus->adapter.algo_data  = dev_priv;
@@ -406,10 +399,10 @@ int intel_setup_gmbus(struct drm_device *dev)
goto err;

/* By default use a conservative clock rate */
-   bus->reg0 = i | GMBUS_RATE_100KHZ;
+   bus->reg0 = port | GMBUS_RATE_100KHZ;

/* XXX force bit banging until GMBUS is fully debugged */
-   bus->force_bit = intel_gpio_create(dev_priv, i);
+   bus->force_bit = 

[PATCH 03/10 v2] drm/i915/intel_i2c: add intel_gmbus_get_adapter

2012-03-10 Thread Daniel Kurtz
Instead of letting other modules directly access the ->gmbus array,
introduce a new API, intel_gmbus_get_adapter(), to lookup an i2c_adapter
for a given gmbus pin pair identifier.  This API enables later refactoring
of the gmbus pin pair list.

Note: It is critical that intel_setup_gmbus() gets called before
intel_gmbus_get_adapter().

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/i915_drv.h|4 +++-
 drivers/gpu/drm/i915/intel_bios.c  |   11 +++
 drivers/gpu/drm/i915/intel_crt.c   |   13 ++---
 drivers/gpu/drm/i915/intel_drv.h   |3 ++-
 drivers/gpu/drm/i915/intel_dvo.c   |4 ++--
 drivers/gpu/drm/i915/intel_hdmi.c  |   29 ++---
 drivers/gpu/drm/i915/intel_i2c.c   |7 +++
 drivers/gpu/drm/i915/intel_lvds.c  |3 ++-
 drivers/gpu/drm/i915/intel_modes.c |6 +++---
 drivers/gpu/drm/i915/intel_sdvo.c  |   10 --
 10 files changed, 50 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9689ca3..9a81e48 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -391,7 +391,7 @@ typedef struct drm_i915_private {

struct notifier_block lid_notifier;

-   int crt_ddc_pin;
+   struct i2c_adapter *crt_ddc;
struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 
965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -1274,6 +1274,8 @@ extern int i915_restore_state(struct drm_device *dev);
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
 extern void intel_teardown_gmbus(struct drm_device *dev);
+extern struct i2c_adapter *intel_gmbus_get_adapter(
+   struct drm_i915_private *dev_priv, unsigned pin);
 extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
 extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
 extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
diff --git a/drivers/gpu/drm/i915/intel_bios.c 
b/drivers/gpu/drm/i915/intel_bios.c
index 63880e2..00e751f 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -330,12 +330,14 @@ parse_general_definitions(struct drm_i915_private 
*dev_priv,
u16 block_size = get_blocksize(general);
if (block_size >= sizeof(*general)) {
int bus_pin = general->crt_ddc_gmbus_pin;
+   struct i2c_adapter *i2c;
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
-   if (bus_pin >= 1 && bus_pin <= 6)
-   dev_priv->crt_ddc_pin = bus_pin;
+   i2c = intel_gmbus_get_adapter(dev_priv, bus_pin);
+   if (i2c)
+   dev_priv->crt_ddc = i2c;
} else {
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
- block_size);
+ block_size);
}
}
 }
@@ -599,7 +601,8 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
 {
struct drm_device *dev = dev_priv->dev;

-   dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+   dev_priv->crt_ddc = intel_gmbus_get_adapter(dev_priv,
+   GMBUS_PORT_VGADDC);

/* LFP panel data */
dev_priv->lvds_dither = 1;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index dd729d4..02f6fc1 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -275,12 +275,11 @@ static bool intel_crt_detect_ddc(struct drm_connector 
*connector)
if (crt->base.type != INTEL_OUTPUT_ANALOG)
return false;

-   if (intel_ddc_probe(>base, dev_priv->crt_ddc_pin)) {
+   if (intel_ddc_probe(>base, dev_priv->crt_ddc)) {
struct edid *edid;
bool is_digital = false;

-   edid = drm_get_edid(connector,
-   _priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+   edid = drm_get_edid(connector, dev_priv->crt_ddc);
/*
 * This may be a DVI-I connector with a shared DDC
 * link between analog and digital outputs, so we
@@ -484,14 +483,14 @@ static int intel_crt_get_modes(struct drm_connector 
*connector)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;

-   ret = intel_ddc_get_modes(connector,
-
_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+   ret = intel_ddc_get_modes(connector, dev_priv->crt_ddc);
if (ret || !IS_G4X(dev))
return ret;

/* Try to probe digital port for output in DVI-I -> VGA mode. */
-   return intel_ddc_get_modes(connector,
- 

[PATCH 02/10 v2] drm/i915/intel_i2c: assign HDMI port D to pin pair 6

2012-03-10 Thread Daniel Kurtz
According to i915 documentation [1], "Port D" (DP/HDMI Port D) is
actually gmbus pin pair 6 (gmbus0.2:0 == 110b GPIOF), not 7 (111b).
Pin pair 7 is a reserved pair.

[1] Documentation for [DevSNB+] and [DevIBX], as found on
http://intellinuxgraphics.org

Note: the "reserved" and "disabled" pairs do not actually map to a
physical pair of pins, nor GPIO regs and shouldn't be initialized or used.
Fixing this is left for a later patch.

This bug has not been noticed for two reasons:
 1) "gmbus" mode is currently disabled - all transfers are actually using
"bit-bang" mode which uses the GPIO port 5 (the "HDMI/DPD CTLDATA/CLK"
pair), at register 0x5024 (defined as GPIOF i915_reg.h).
Since this is the correct pair of pins for HDMI1, transfers succeed.

 2) Even if gmbus mode is re-enabled, the first attempted transaction
will fail because it tries to use the wrong ("Reserved") pin pair.
However, the driver immediately falls back again to the bit-bang
method, which correctly uses GPIOF, so again, transfers succeed.

However, if gmbus mode is re-enabled and the GPIO fall-back mode is
disabled, then reading an attached monitor's EDID fail.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/i915_reg.h  |6 +++---
 drivers/gpu/drm/i915/intel_i2c.c |6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 03c53fc..56af0df 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -697,9 +697,9 @@
 #define   GMBUS_PORT_PANEL 3
 #define   GMBUS_PORT_DPC   4 /* HDMIC */
 #define   GMBUS_PORT_DPB   5 /* SDVO, HDMIB */
- /* 6 reserved */
-#define   GMBUS_PORT_DPD   7 /* HDMID */
-#define   GMBUS_NUM_PORTS   8
+#define   GMBUS_PORT_DPD   6 /* HDMID */
+#define   GMBUS_PORT_RESERVED  7 /* 7 reserved */
+#define   GMBUS_NUM_PORTS  8
 #define GMBUS1 0x5104 /* command/status */
 #define   GMBUS_SW_CLR_INT (1<<31)
 #define   GMBUS_SW_RDY (1<<30)
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 5e413c4..1135e3e 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -157,8 +157,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 
pin)
GPIOC,
GPIOD,
GPIOE,
-   0,
GPIOF,
+   0,
};
struct intel_gpio *gpio;

@@ -175,7 +175,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 
pin)
gpio->dev_priv = dev_priv;

snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
-"i915 GPIO%c", "?BACDE?F"[pin]);
+"i915 GPIO%c", "?BACDEF?"[pin]);
gpio->adapter.owner = THIS_MODULE;
gpio->adapter.algo_data = >algo;
gpio->adapter.dev.parent = _priv->dev->pdev->dev;
@@ -376,8 +376,8 @@ int intel_setup_gmbus(struct drm_device *dev)
"panel",
"dpc",
"dpb",
-   "reserved",
"dpd",
+   "reserved",
};
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i;
-- 
1.7.7.3



[PATCH 01/10 v2] drm/i915/intel_i2c: cleanup

2012-03-10 Thread Daniel Kurtz
80 col, spaces around operators and other basic cleanup.

Signed-off-by: Daniel Kurtz 
---
 drivers/gpu/drm/i915/intel_i2c.c |   19 +--
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d30..5e413c4 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -253,11 +253,13 @@ gmbus_xfer(struct i2c_adapter *adapter,
   (len << GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);
do {
u32 val, loop = 0;

-   if (wait_for(I915_READ(GMBUS2 + reg_offset) & 
(GMBUS_SATOER | GMBUS_HW_RDY), 50))
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & 
GMBUS_SATOER)
goto clear_err;
@@ -282,10 +284,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);

while (len) {
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) & 
(GMBUS_SATOER | GMBUS_HW_RDY), 50))
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) &
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & 
GMBUS_SATOER)
goto clear_err;
@@ -296,11 +300,14 @@ gmbus_xfer(struct i2c_adapter *adapter,
} while (--len && ++loop < 4);

I915_WRITE(GMBUS3 + reg_offset, val);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);
}
}

-   if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & 
(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+   if (i + 1 < num &&
+   wait_for(I915_READ(GMBUS2 + reg_offset) &
+(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
goto clear_err;
-- 
1.7.7.3



[PATCH 00/10 v2] fix gmbus writes and related issues

2012-03-10 Thread Daniel Kurtz
This patchset addresses a couple of issues with the i915 gmbus implementation:
 * fixes misassigned pin port pair for HDMI-D
 * fixes write transactions when they are the only transaction requested
   (including large >4-byte writes) by terminating every transaction with a
   WAIT cycle.
 * returns -ENXIO and -ETIMEDOUT as appropriate so upper layers can handled
   i2c transaction failures
 * optimizes the typical read transaction case by using the INDEX cycle
 * turns on the GMBUS interrupt whenever possible to dramatically improve
   throughput by eliminating the very slow polling loop.

The patchset should apply cleanly onto linus/master.
It is inspired by, but completely supercedes, a similar patch submitted
recently by Benson Leung (bleung at chromium.org).
I'd be happy to rebase on a different tree if necessary.

v2 of the patchset address review comments from Chris Wilson (thanks for the
review, Chris!), and adds the interrupt patch.  There weren't any review
comments for patches 5, 7, or 8 of the first set.  Hopefully they will get
more love the second time around :).


Daniel Kurtz (10):
  drm/i915/intel_i2c: cleanup
  drm/i915/intel_i2c: assign HDMI port D to pin pair 6
  drm/i915/intel_i2c: refactor using intel_gmbus_get_adapter
  drm/i915/intel_i2c: cleanup gmbus/gpio pin assignments
  drm/i915/intel_i2c: add locking around i2c algorithm accesses
  drm/i915/intel_i2c: return -ENXIO for device NAK
  drm/i915/intel_i2c: use WAIT cycle, not STOP
  drm/i915/intel_i2c: use INDEX cycles for i2c read transactions
  drm/i915/intel_i2c: reuse GMBUS2 value read in polling loop
  drm/i915/intel_i2c: enable gmbus interrupts

 drivers/gpu/drm/i915/i915_drv.h|7 +-
 drivers/gpu/drm/i915/i915_irq.c|   22 +++-
 drivers/gpu/drm/i915/i915_reg.h|6 +-
 drivers/gpu/drm/i915/intel_bios.c  |   11 +-
 drivers/gpu/drm/i915/intel_crt.c   |   13 +-
 drivers/gpu/drm/i915/intel_drv.h   |9 ++-
 drivers/gpu/drm/i915/intel_dvo.c   |4 +-
 drivers/gpu/drm/i915/intel_hdmi.c  |   29 ++---
 drivers/gpu/drm/i915/intel_i2c.c   |  236 
 drivers/gpu/drm/i915/intel_lvds.c  |3 +-
 drivers/gpu/drm/i915/intel_modes.c |6 +-
 drivers/gpu/drm/i915/intel_sdvo.c  |   10 +-
 12 files changed, 257 insertions(+), 99 deletions(-)

-- 
1.7.7.3



[Bug 47162] Screen went black for seconds, 100% cpu usage on dri2Throttle/sched_yield

2012-03-10 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=47162

Michel Dänzer mic...@daenzer.net changed:

   What|Removed |Added

 AssignedTo|xorg-driver-...@lists.x.org |dri-devel@lists.freedesktop
   ||.org
  QAContact|xorg-t...@lists.x.org   |
Product|xorg|Mesa
Version|7.4 (2008.09)   |8.0
  Component|Driver/Radeon   |Drivers/Gallium/r600

--- Comment #1 from Michel Dänzer mic...@daenzer.net 2012-03-10 01:19:06 PST 
---
(In reply to comment #1)
 OpenGL version string: 2.1 Mesa 8.0

The r600g driver from Mesa 8.0.1 or newer should deal with this more
gracefully.

-- 
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
--- You are receiving this mail because: ---
You are the assignee for the bug.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 00/10 v2] fix gmbus writes and related issues

2012-03-10 Thread Daniel Kurtz
This patchset addresses a couple of issues with the i915 gmbus implementation:
 * fixes misassigned pin port pair for HDMI-D
 * fixes write transactions when they are the only transaction requested
   (including large 4-byte writes) by terminating every transaction with a
   WAIT cycle.
 * returns -ENXIO and -ETIMEDOUT as appropriate so upper layers can handled
   i2c transaction failures
 * optimizes the typical read transaction case by using the INDEX cycle
 * turns on the GMBUS interrupt whenever possible to dramatically improve
   throughput by eliminating the very slow polling loop.

The patchset should apply cleanly onto linus/master.
It is inspired by, but completely supercedes, a similar patch submitted
recently by Benson Leung (ble...@chromium.org).
I'd be happy to rebase on a different tree if necessary.

v2 of the patchset address review comments from Chris Wilson (thanks for the
review, Chris!), and adds the interrupt patch.  There weren't any review
comments for patches 5, 7, or 8 of the first set.  Hopefully they will get
more love the second time around :).


Daniel Kurtz (10):
  drm/i915/intel_i2c: cleanup
  drm/i915/intel_i2c: assign HDMI port D to pin pair 6
  drm/i915/intel_i2c: refactor using intel_gmbus_get_adapter
  drm/i915/intel_i2c: cleanup gmbus/gpio pin assignments
  drm/i915/intel_i2c: add locking around i2c algorithm accesses
  drm/i915/intel_i2c: return -ENXIO for device NAK
  drm/i915/intel_i2c: use WAIT cycle, not STOP
  drm/i915/intel_i2c: use INDEX cycles for i2c read transactions
  drm/i915/intel_i2c: reuse GMBUS2 value read in polling loop
  drm/i915/intel_i2c: enable gmbus interrupts

 drivers/gpu/drm/i915/i915_drv.h|7 +-
 drivers/gpu/drm/i915/i915_irq.c|   22 +++-
 drivers/gpu/drm/i915/i915_reg.h|6 +-
 drivers/gpu/drm/i915/intel_bios.c  |   11 +-
 drivers/gpu/drm/i915/intel_crt.c   |   13 +-
 drivers/gpu/drm/i915/intel_drv.h   |9 ++-
 drivers/gpu/drm/i915/intel_dvo.c   |4 +-
 drivers/gpu/drm/i915/intel_hdmi.c  |   29 ++---
 drivers/gpu/drm/i915/intel_i2c.c   |  236 
 drivers/gpu/drm/i915/intel_lvds.c  |3 +-
 drivers/gpu/drm/i915/intel_modes.c |6 +-
 drivers/gpu/drm/i915/intel_sdvo.c  |   10 +-
 12 files changed, 257 insertions(+), 99 deletions(-)

-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 08/10 v2] drm/i915/intel_i2c: use INDEX cycles for i2c read transactions

2012-03-10 Thread Daniel Kurtz
It is very common for an i2c device to require a small 1 or 2 byte write
followed by a read.  For example, when reading from an i2c EEPROM it is
common to write and address, offset or index followed by a reading some
values.

The i915 gmbus controller provides a special INDEX cycle for performing
such a small write followed by a read.  The INDEX can be either one or two
bytes long.  The advantage of using such a cycle is that the CPU has
slightly less work to do once the read with INDEX cycle is started.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/intel_i2c.c |   32 ++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index b79a181..61fe317 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -255,12 +255,40 @@ gmbus_xfer(struct i2c_adapter *adapter,
I915_WRITE(GMBUS0 + reg_offset, bus-reg0);
 
for (i = 0; i  num; i++) {
-   u16 len = msgs[i].len;
-   u8 *buf = msgs[i].buf;
+   u16 len;
+   u8 *buf;
+   u32 gmbus5 = 0;
+   u32 gmbus1_index = 0;
+
+   /*
+* The gmbus controller can combine a 1 or 2 byte write with a
+* read that immediately follows it by using an INDEX cycle.
+*/
+   if (i + 1  num 
+   !(msgs[i].flags  I2C_M_RD) 
+   (msgs[i + 1].flags  I2C_M_RD) 
+   msgs[i].len = 2) {
+   if (msgs[i].len == 2)
+   gmbus5 = GMBUS_2BYTE_INDEX_EN |
+msgs[i].buf[1] |
+(msgs[i].buf[0]  8);
+   if (msgs[i].len == 1)
+   gmbus1_index = GMBUS_CYCLE_INDEX |
+  (msgs[i].buf[0] 
+   GMBUS_SLAVE_INDEX_SHIFT);
+   i += 1;  /* set i to the index of the read xfer */
+   }
+
+   len = msgs[i].len;
+   buf = msgs[i].buf;
+
+   /* GMBUS5 holds 16-bit index, but must be 0 if not used */
+   I915_WRITE(GMBUS5 + reg_offset, gmbus5);
 
if (msgs[i].flags  I2C_M_RD) {
I915_WRITE(GMBUS1 + reg_offset,
   GMBUS_CYCLE_WAIT |
+  gmbus1_index |
   (len  GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr  GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: BUG: drm_crtc_helper_set_config does not work

2012-03-10 Thread Yufeng Shen
On Fri, Mar 9, 2012 at 3:15 AM, Maarten Maathuis madman2...@gmail.com wrote:
 On Fri, Mar 9, 2012 at 2:50 AM, Yufeng Shen mile...@chromium.org wrote:
 So a simple case of  disabling a CRTC and then re-enabling it.

 Disabling:

 CRTC X is originally connected to output Y

 1. XRRSetCrtcConfig()    is called to disable CRTC  X

 2. drm_helper_connector_dpms()   then gets called on the connector
 connected to CRTC X,
    in the function,
    the  connector-encoder  is set to DPMS OFF,   and the
 encoder-crtc  set to DPMS OFF
    but the  encoder-crtc   is still CRTC X

 Re-enabling:

 3. XRRSetCrtcConfig()    is called to to enable CRTC  X  on output Y

 4. drm_crtc_helper_set_config ()  is now called,
 suppose   fb is not changed,  mode is not changed, encoder is not changed
 and the   encoder-crtc  is not changed,
 then we have   mode_changed == false    and  the mode is not reset

 So the CRTC X won't be connected to output Y.

 What I don't understand the code is that why  XRRSetCrtcConfig()  ends
 up only calling  drm_helper_connector_dpms()  ?
 I think it should do more than that, at least it should set the
 related  encoder-crtc = NULL

 any comments ?
 ___
 dri-devel mailing list
 dri-devel@lists.freedesktop.org
 http://lists.freedesktop.org/mailman/listinfo/dri-devel

 As far as i know DPMS designed is a simple switch, meaning that the
 mode remains active, so if you do DPMS ON it should come back. If for
 some reason the driver is disconnecting the encoder from the crtc,
 then it is the drivers responsibility to reconnect it when DPMS ON
 happens.

 But don't take my word for it, others may have more/other information.


Yes, I was thinking ideally DPMS call should enable/disable DPMS state, and
XRRSetCrtcConfig call should enable/disable CRTC.

But it seems that, when using XRRSetCrtcConfig to disable CRTC,
the CRTC itself is disabled, the DPMS is disabled (DPMS OFF),
and then when using XRRSetCrtcConfig to re-enable the CRTC,
it only checks whether the CRTC that connected to the encoder is
changed (whether a new crtc is assigned), but does not check whether
the CRTC itself is previously disabled or not.  So it considers the encoder
is connected to the same CRTC and does no thing to re-enable the CRTC.


 --
 Far away from the primal instinct, the song seems to fade away, the
 river get wider between your thoughts and the things we do and say.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 03/10 v2] drm/i915/intel_i2c: add intel_gmbus_get_adapter

2012-03-10 Thread Daniel Kurtz
Instead of letting other modules directly access the -gmbus array,
introduce a new API, intel_gmbus_get_adapter(), to lookup an i2c_adapter
for a given gmbus pin pair identifier.  This API enables later refactoring
of the gmbus pin pair list.

Note: It is critical that intel_setup_gmbus() gets called before
intel_gmbus_get_adapter().

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/i915_drv.h|4 +++-
 drivers/gpu/drm/i915/intel_bios.c  |   11 +++
 drivers/gpu/drm/i915/intel_crt.c   |   13 ++---
 drivers/gpu/drm/i915/intel_drv.h   |3 ++-
 drivers/gpu/drm/i915/intel_dvo.c   |4 ++--
 drivers/gpu/drm/i915/intel_hdmi.c  |   29 ++---
 drivers/gpu/drm/i915/intel_i2c.c   |7 +++
 drivers/gpu/drm/i915/intel_lvds.c  |3 ++-
 drivers/gpu/drm/i915/intel_modes.c |6 +++---
 drivers/gpu/drm/i915/intel_sdvo.c  |   10 --
 10 files changed, 50 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9689ca3..9a81e48 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -391,7 +391,7 @@ typedef struct drm_i915_private {
 
struct notifier_block lid_notifier;
 
-   int crt_ddc_pin;
+   struct i2c_adapter *crt_ddc;
struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 
965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -1274,6 +1274,8 @@ extern int i915_restore_state(struct drm_device *dev);
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
 extern void intel_teardown_gmbus(struct drm_device *dev);
+extern struct i2c_adapter *intel_gmbus_get_adapter(
+   struct drm_i915_private *dev_priv, unsigned pin);
 extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
 extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
 extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
diff --git a/drivers/gpu/drm/i915/intel_bios.c 
b/drivers/gpu/drm/i915/intel_bios.c
index 63880e2..00e751f 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -330,12 +330,14 @@ parse_general_definitions(struct drm_i915_private 
*dev_priv,
u16 block_size = get_blocksize(general);
if (block_size = sizeof(*general)) {
int bus_pin = general-crt_ddc_gmbus_pin;
+   struct i2c_adapter *i2c;
DRM_DEBUG_KMS(crt_ddc_bus_pin: %d\n, bus_pin);
-   if (bus_pin = 1  bus_pin = 6)
-   dev_priv-crt_ddc_pin = bus_pin;
+   i2c = intel_gmbus_get_adapter(dev_priv, bus_pin);
+   if (i2c)
+   dev_priv-crt_ddc = i2c;
} else {
DRM_DEBUG_KMS(BDB_GD too small (%d). Invalid.\n,
- block_size);
+ block_size);
}
}
 }
@@ -599,7 +601,8 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
 {
struct drm_device *dev = dev_priv-dev;
 
-   dev_priv-crt_ddc_pin = GMBUS_PORT_VGADDC;
+   dev_priv-crt_ddc = intel_gmbus_get_adapter(dev_priv,
+   GMBUS_PORT_VGADDC);
 
/* LFP panel data */
dev_priv-lvds_dither = 1;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index dd729d4..02f6fc1 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -275,12 +275,11 @@ static bool intel_crt_detect_ddc(struct drm_connector 
*connector)
if (crt-base.type != INTEL_OUTPUT_ANALOG)
return false;
 
-   if (intel_ddc_probe(crt-base, dev_priv-crt_ddc_pin)) {
+   if (intel_ddc_probe(crt-base, dev_priv-crt_ddc)) {
struct edid *edid;
bool is_digital = false;
 
-   edid = drm_get_edid(connector,
-   dev_priv-gmbus[dev_priv-crt_ddc_pin].adapter);
+   edid = drm_get_edid(connector, dev_priv-crt_ddc);
/*
 * This may be a DVI-I connector with a shared DDC
 * link between analog and digital outputs, so we
@@ -484,14 +483,14 @@ static int intel_crt_get_modes(struct drm_connector 
*connector)
struct drm_i915_private *dev_priv = dev-dev_private;
int ret;
 
-   ret = intel_ddc_get_modes(connector,
-
dev_priv-gmbus[dev_priv-crt_ddc_pin].adapter);
+   ret = intel_ddc_get_modes(connector, dev_priv-crt_ddc);
if (ret || !IS_G4X(dev))
return ret;
 
/* Try to probe digital port for output in DVI-I - VGA mode. */
-   return intel_ddc_get_modes(connector,
- 

[PATCH 02/10 v2] drm/i915/intel_i2c: assign HDMI port D to pin pair 6

2012-03-10 Thread Daniel Kurtz
According to i915 documentation [1], Port D (DP/HDMI Port D) is
actually gmbus pin pair 6 (gmbus0.2:0 == 110b GPIOF), not 7 (111b).
Pin pair 7 is a reserved pair.

[1] Documentation for [DevSNB+] and [DevIBX], as found on
http://intellinuxgraphics.org

Note: the reserved and disabled pairs do not actually map to a
physical pair of pins, nor GPIO regs and shouldn't be initialized or used.
Fixing this is left for a later patch.

This bug has not been noticed for two reasons:
 1) gmbus mode is currently disabled - all transfers are actually using
bit-bang mode which uses the GPIO port 5 (the HDMI/DPD CTLDATA/CLK
pair), at register 0x5024 (defined as GPIOF i915_reg.h).
Since this is the correct pair of pins for HDMI1, transfers succeed.

 2) Even if gmbus mode is re-enabled, the first attempted transaction
will fail because it tries to use the wrong (Reserved) pin pair.
However, the driver immediately falls back again to the bit-bang
method, which correctly uses GPIOF, so again, transfers succeed.

However, if gmbus mode is re-enabled and the GPIO fall-back mode is
disabled, then reading an attached monitor's EDID fail.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/i915_reg.h  |6 +++---
 drivers/gpu/drm/i915/intel_i2c.c |6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 03c53fc..56af0df 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -697,9 +697,9 @@
 #define   GMBUS_PORT_PANEL 3
 #define   GMBUS_PORT_DPC   4 /* HDMIC */
 #define   GMBUS_PORT_DPB   5 /* SDVO, HDMIB */
- /* 6 reserved */
-#define   GMBUS_PORT_DPD   7 /* HDMID */
-#define   GMBUS_NUM_PORTS   8
+#define   GMBUS_PORT_DPD   6 /* HDMID */
+#define   GMBUS_PORT_RESERVED  7 /* 7 reserved */
+#define   GMBUS_NUM_PORTS  8
 #define GMBUS1 0x5104 /* command/status */
 #define   GMBUS_SW_CLR_INT (131)
 #define   GMBUS_SW_RDY (130)
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 5e413c4..1135e3e 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -157,8 +157,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 
pin)
GPIOC,
GPIOD,
GPIOE,
-   0,
GPIOF,
+   0,
};
struct intel_gpio *gpio;
 
@@ -175,7 +175,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 
pin)
gpio-dev_priv = dev_priv;
 
snprintf(gpio-adapter.name, sizeof(gpio-adapter.name),
-i915 GPIO%c, ?BACDE?F[pin]);
+i915 GPIO%c, ?BACDEF?[pin]);
gpio-adapter.owner = THIS_MODULE;
gpio-adapter.algo_data = gpio-algo;
gpio-adapter.dev.parent = dev_priv-dev-pdev-dev;
@@ -376,8 +376,8 @@ int intel_setup_gmbus(struct drm_device *dev)
panel,
dpc,
dpb,
-   reserved,
dpd,
+   reserved,
};
struct drm_i915_private *dev_priv = dev-dev_private;
int ret, i;
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 05/10 v2] drm/i915/intel_i2c: add locking around i2c algorithm accesses

2012-03-10 Thread Daniel Kurtz
The i915 has multiple i2c adapters.  However, they all share a single
single set of i2c control registers (algorithm).  Thus, different threads
trying to access different adapters could interfere with each other.

Note: different threads trying to access the same channel is already
handled in the i2c-core using the i2c adapter lock.

This patch adds a mutex to serialize access to the gmbus_xfer routine.
Note: the same mutex serializes both bit banged and native xfers.

Signed-off-by: Yufeng Shen mile...@chromium.org
Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/i915_drv.h  |1 +
 drivers/gpu/drm/i915/intel_i2c.c |   13 +
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9a81e48..68aef65 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -301,6 +301,7 @@ typedef struct drm_i915_private {
struct i2c_adapter *force_bit;
u32 reg0;
} *gmbus;
+   struct mutex gmbus_mutex;
 
struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index f53f525..232b7cb 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -212,6 +212,8 @@ intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
   adapter);
int ret;
 
+   mutex_lock(dev_priv-gmbus_mutex);
+
intel_i2c_reset(dev_priv-dev);
 
intel_i2c_quirk_set(dev_priv, true);
@@ -225,6 +227,8 @@ intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
set_clock(gpio, 1);
intel_i2c_quirk_set(dev_priv, false);
 
+   mutex_unlock(dev_priv-gmbus_mutex);
+
return ret;
 }
 
@@ -243,6 +247,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
return intel_i2c_quirk_xfer(dev_priv,
bus-force_bit, msgs, num);
 
+   mutex_lock(dev_priv-gmbus_mutex);
+
reg_offset = HAS_PCH_SPLIT(dev_priv-dev) ? PCH_GMBUS0 - GMBUS0 : 0;
 
I915_WRITE(GMBUS0 + reg_offset, bus-reg0);
@@ -332,6 +338,9 @@ done:
 * start of the next xfer, till then let it sleep.
 */
I915_WRITE(GMBUS0 + reg_offset, 0);
+
+   mutex_unlock(dev_priv-gmbus_mutex);
+
return i;
 
 timeout:
@@ -339,6 +348,8 @@ timeout:
 bus-reg0  0xff, bus-adapter.name);
I915_WRITE(GMBUS0 + reg_offset, 0);
 
+   mutex_unlock(dev_priv-gmbus_mutex);
+
/* 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)
@@ -381,6 +392,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  ARRAY_SIZE(gmbus_ports); i++) {
struct intel_gmbus *bus = dev_priv-gmbus[i];
u32 port = i + 1; /* +1 to map gmbus index to pin pair */
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 04/10 v2] drm/i915/intel_i2c: cleanup gmbus/gpio pin assignments

2012-03-10 Thread Daniel Kurtz
There is no disabled port 0.  So, don't even try to initialize/scan
it, etc.  This saves a bit of time when initializing the driver, since
it avoids a 50ms timeout waiting for a device to respond on a port that
doesn't even exist.

Similarly, don't initialize the reserved port 7, either.

Tested on Sandybridge (gen 6, PCH == CougarPoint) hardware.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/i915_reg.h  |1 -
 drivers/gpu/drm/i915/intel_i2c.c |   64 +
 2 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 56af0df..89cace2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -699,7 +699,6 @@
 #define   GMBUS_PORT_DPB   5 /* SDVO, HDMIB */
 #define   GMBUS_PORT_DPD   6 /* HDMID */
 #define   GMBUS_PORT_RESERVED  7 /* 7 reserved */
-#define   GMBUS_NUM_PORTS  8
 #define GMBUS1 0x5104 /* command/status */
 #define   GMBUS_SW_CLR_INT (131)
 #define   GMBUS_SW_RDY (130)
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 87a3abf..f53f525 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -35,6 +35,20 @@
 #include i915_drm.h
 #include i915_drv.h
 
+struct gmbus_port {
+   const char *name;
+   int reg;
+};
+
+static const struct gmbus_port gmbus_ports[] = {
+   { ssc, GPIOB },
+   { vga, GPIOA },
+   { panel, GPIOC },
+   { dpc, GPIOD },
+   { dpb, GPIOE },
+   { dpd, GPIOF },
+};
+
 /* Intel GPIO access functions */
 
 #define I2C_RISEFALL_TIME 20
@@ -150,32 +164,22 @@ static void set_data(void *data, int state_high)
 static struct i2c_adapter *
 intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-   static const int map_pin_to_reg[] = {
-   0,
-   GPIOB,
-   GPIOA,
-   GPIOC,
-   GPIOD,
-   GPIOE,
-   GPIOF,
-   0,
-   };
struct intel_gpio *gpio;
 
-   if (pin = ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
-   return NULL;
+   pin -= 1;  /* NB: -1 to map pin pair to gmbus array index */
+   BUG_ON(pin = ARRAY_SIZE(gmbus_ports));
 
gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
if (gpio == NULL)
return NULL;
 
-   gpio-reg = map_pin_to_reg[pin];
+   gpio-reg = gmbus_ports[pin].reg;
if (HAS_PCH_SPLIT(dev_priv-dev))
gpio-reg += PCH_GPIOA - GPIOA;
gpio-dev_priv = dev_priv;
 
snprintf(gpio-adapter.name, sizeof(gpio-adapter.name),
-i915 GPIO%c, ?BACDEF?[pin]);
+i915 GPIO%c, BACDEF[pin]);
gpio-adapter.owner = THIS_MODULE;
gpio-adapter.algo_data = gpio-algo;
gpio-adapter.dev.parent = dev_priv-dev-pdev-dev;
@@ -369,33 +373,22 @@ static const struct i2c_algorithm gmbus_algorithm = {
  */
 int intel_setup_gmbus(struct drm_device *dev)
 {
-   static const char *names[GMBUS_NUM_PORTS] = {
-   disabled,
-   ssc,
-   vga,
-   panel,
-   dpc,
-   dpb,
-   dpd,
-   reserved,
-   };
struct drm_i915_private *dev_priv = dev-dev_private;
int ret, i;
 
-   dev_priv-gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
- GFP_KERNEL);
+   dev_priv-gmbus = kcalloc(sizeof(struct intel_gmbus),
+ ARRAY_SIZE(gmbus_ports), GFP_KERNEL);
if (dev_priv-gmbus == NULL)
return -ENOMEM;
 
-   for (i = 0; i  GMBUS_NUM_PORTS; i++) {
+   for (i = 0; i  ARRAY_SIZE(gmbus_ports); i++) {
struct intel_gmbus *bus = dev_priv-gmbus[i];
+   u32 port = i + 1; /* +1 to map gmbus index to pin pair */
 
bus-adapter.owner = THIS_MODULE;
bus-adapter.class = I2C_CLASS_DDC;
-   snprintf(bus-adapter.name,
-sizeof(bus-adapter.name),
-i915 gmbus %s,
-names[i]);
+   snprintf(bus-adapter.name, sizeof(bus-adapter.name),
+i915 gmbus %s, gmbus_ports[i].name);
 
bus-adapter.dev.parent = dev-pdev-dev;
bus-adapter.algo_data  = dev_priv;
@@ -406,10 +399,10 @@ int intel_setup_gmbus(struct drm_device *dev)
goto err;
 
/* By default use a conservative clock rate */
-   bus-reg0 = i | GMBUS_RATE_100KHZ;
+   bus-reg0 = port | GMBUS_RATE_100KHZ;
 
/* XXX force bit banging until GMBUS is fully debugged */
-   bus-force_bit = intel_gpio_create(dev_priv, i);
+   bus-force_bit = intel_gpio_create(dev_priv, port);
}
 

[PATCH 09/10 v2] drm/i915/intel_i2c: reuse GMBUS2 value read in polling loop

2012-03-10 Thread Daniel Kurtz
Save the GMBUS2 value read while polling for state changes, and then
reuse this value when determining for which reason the loops were exited.
This is a small optimization which saves a couple of bus accesses for
memory mapped IO registers.

Signed-off-by: Daniel Kurtz djku...@chromium.org
Reviewed-by: Chris Wilson ch...@chris-wilson.co.uk
---
 drivers/gpu/drm/i915/intel_i2c.c |   19 ++-
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 61fe317..2c372d3 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -243,6 +243,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
struct drm_i915_private *dev_priv = adapter-algo_data;
int i, reg_offset;
int ret = 0;
+   u32 gmbus2 = 0;
 
if (bus-force_bit)
return intel_i2c_quirk_xfer(dev_priv,
@@ -296,12 +297,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
do {
u32 val, loop = 0;
 
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 +
+reg_offset)) 
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) 
-   GMBUS_SATOER)
+   if (gmbus2  GMBUS_SATOER)
goto clear_err;
 
val = I915_READ(GMBUS3 + reg_offset);
@@ -335,21 +336,21 @@ gmbus_xfer(struct i2c_adapter *adapter,
I915_WRITE(GMBUS3 + reg_offset, val);
POSTING_READ(GMBUS2 + reg_offset);
 
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 +
+reg_offset)) 
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset) 
- GMBUS_SATOER)
+   if (gmbus2  GMBUS_SATOER)
goto clear_err;
}
}
 
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+   if (wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) 
 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset)  GMBUS_SATOER)
+   if (gmbus2  GMBUS_SATOER)
goto clear_err;
}
 
@@ -373,7 +374,7 @@ clear_err:
ret = -ENXIO;
 
 done:
-   if (I915_READ(GMBUS2 + reg_offset)  GMBUS_HW_WAIT_PHASE) {
+   if (gmbus2  GMBUS_HW_WAIT_PHASE) {
I915_WRITE(GMBUS1 + reg_offset,
   GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
POSTING_READ(GMBUS2 + reg_offset);
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 06/10 v2] drm/i915/intel_i2c: return -ENXIO for device NAK

2012-03-10 Thread Daniel Kurtz
Return -ENXIO if a device NAKs a transaction.

Note: We should return -ETIMEDOUT, too if the transaction times out,
however, that error path is currently handled by the 'bit-bang fallback'.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/intel_i2c.c |   12 +++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 232b7cb..151b828 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -242,6 +242,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
   adapter);
struct drm_i915_private *dev_priv = adapter-algo_data;
int i, reg_offset;
+   int ret = 0;
 
if (bus-force_bit)
return intel_i2c_quirk_xfer(dev_priv,
@@ -333,6 +334,15 @@ clear_err:
I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
I915_WRITE(GMBUS1 + reg_offset, 0);
 
+   /*
+* If no ACK is received during the address phase of a transaction,
+* the adapter must report -ENXIO.
+* It is not clear what to return if no ACK is received at other times.
+* So, we always return -ENXIO in all NAK cases, to ensure we send
+* it at least during the one case that is specified.
+*/
+   ret = -ENXIO;
+
 done:
/* Mark the GMBUS interface as disabled. We will re-enable it at the
 * start of the next xfer, till then let it sleep.
@@ -341,7 +351,7 @@ done:
 
mutex_unlock(dev_priv-gmbus_mutex);
 
-   return i;
+   return ret ?: i;
 
 timeout:
DRM_INFO(GMBUS timed out, falling back to bit banging on pin %d 
[%s]\n,
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 01/10 v2] drm/i915/intel_i2c: cleanup

2012-03-10 Thread Daniel Kurtz
80 col, spaces around operators and other basic cleanup.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/intel_i2c.c |   19 +--
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d30..5e413c4 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -253,11 +253,13 @@ gmbus_xfer(struct i2c_adapter *adapter,
   (len  GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr  GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);
do {
u32 val, loop = 0;
 
-   if (wait_for(I915_READ(GMBUS2 + reg_offset)  
(GMBUS_SATOER | GMBUS_HW_RDY), 50))
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset)  
GMBUS_SATOER)
goto clear_err;
@@ -282,10 +284,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
   (msgs[i].len  GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr  GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);
 
while (len) {
-   if (wait_for(I915_READ(GMBUS2 + reg_offset)  
(GMBUS_SATOER | GMBUS_HW_RDY), 50))
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset)  
GMBUS_SATOER)
goto clear_err;
@@ -296,11 +300,14 @@ gmbus_xfer(struct i2c_adapter *adapter,
} while (--len  ++loop  4);
 
I915_WRITE(GMBUS3 + reg_offset, val);
-   POSTING_READ(GMBUS2+reg_offset);
+   POSTING_READ(GMBUS2 + reg_offset);
}
}
 
-   if (i + 1  num  wait_for(I915_READ(GMBUS2 + reg_offset)  
(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+   if (i + 1  num 
+   wait_for(I915_READ(GMBUS2 + reg_offset) 
+(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
+50))
goto timeout;
if (I915_READ(GMBUS2 + reg_offset)  GMBUS_SATOER)
goto clear_err;
-- 
1.7.7.3

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 10/10 v2] drm/i915/intel_i2c: enable gmbus interrupts

2012-03-10 Thread Daniel Kurtz
Instead of polling for gmbus state changes, use the corresponding gmbus
interrupts, when possible.

There are still some cases where using the GMBUS interrupts is not
possible.  For instance, this patch only enables the interrupt for
ironlake (+ sandy bridge), and ivybridge.  It does not enable them for the
older i915 path through the driver.  Also, there are cases where a gmbus
transaction may be requested before irqs have even been enabled.

For this reason, the older polling loop is left in place, as a backup.

Also, since the interrupts can be enabled/disabled completely
asynchronously from any active gmbus transactions, changing the interrupt
enable is protected by the gmbus transaction mutex.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/i915_drv.h  |2 +
 drivers/gpu/drm/i915/i915_irq.c  |   22 +-
 drivers/gpu/drm/i915/i915_reg.h  |1 +
 drivers/gpu/drm/i915/intel_drv.h |6 +++
 drivers/gpu/drm/i915/intel_i2c.c |   82 --
 5 files changed, 97 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 68aef65..156ad6d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -302,6 +302,8 @@ typedef struct drm_i915_private {
u32 reg0;
} *gmbus;
struct mutex gmbus_mutex;
+   wait_queue_head_t gmbus_waitq;
+   bool gmbus_irq_enabled;
 
struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5bd4361..12a2259 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -432,13 +432,23 @@ static void pch_irq_handler(struct drm_device *dev)
 
pch_iir = I915_READ(SDEIIR);
 
+   if (HAS_PCH_CPT(dev)) {
+   if (pch_iir  SDE_GMBUS_CPT) {
+   DRM_DEBUG_DRIVER(PCH GMBUS interrupt\n);
+   intel_gmbus_irq(dev);
+   }
+   return;
+   }
+
if (pch_iir  SDE_AUDIO_POWER_MASK)
DRM_DEBUG_DRIVER(PCH audio power change on port %d\n,
 (pch_iir  SDE_AUDIO_POWER_MASK) 
 SDE_AUDIO_POWER_SHIFT);
 
-   if (pch_iir  SDE_GMBUS)
+   if (pch_iir  SDE_GMBUS) {
DRM_DEBUG_DRIVER(PCH GMBUS interrupt\n);
+   intel_gmbus_irq(dev);
+   }
 
if (pch_iir  SDE_AUDIO_HDCP_MASK)
DRM_DEBUG_DRIVER(PCH HDCP audio interrupt\n);
@@ -1847,13 +1857,15 @@ static int ironlake_irq_postinstall(struct drm_device 
*dev)
hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
SDE_PORTB_HOTPLUG_CPT |
SDE_PORTC_HOTPLUG_CPT |
-   SDE_PORTD_HOTPLUG_CPT);
+   SDE_PORTD_HOTPLUG_CPT |
+   SDE_GMBUS_CPT);
} else {
hotplug_mask = (SDE_CRT_HOTPLUG |
SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG |
SDE_PORTD_HOTPLUG |
-   SDE_AUX_MASK);
+   SDE_AUX_MASK |
+   SDE_GMBUS);
}
 
dev_priv-pch_irq_mask = ~hotplug_mask;
@@ -1863,6 +1875,7 @@ static int ironlake_irq_postinstall(struct drm_device 
*dev)
I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER);
 
+   intel_gmbus_irq_enable(dev);
ironlake_enable_pch_hotplug(dev);
 
if (IS_IRONLAKE_M(dev)) {
@@ -1922,6 +1935,7 @@ static int ivybridge_irq_postinstall(struct drm_device 
*dev)
I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER);
 
+   intel_gmbus_irq_enable(dev);
ironlake_enable_pch_hotplug(dev);
 
return 0;
@@ -2049,6 +2063,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(GTIER, 0x0);
I915_WRITE(GTIIR, I915_READ(GTIIR));
 
+   intel_gmbus_irq_disable(dev);
+
I915_WRITE(SDEIMR, 0x);
I915_WRITE(SDEIER, 0x0);
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 89cace2..94333e8 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3080,6 +3080,7 @@
 #define SDE_TRANSA_FIFO_UNDER  (1  0)
 #define SDE_TRANS_MASK (0x3f)
 /* CPT */
+#define SDE_GMBUS_CPT  (1  17)
 #define SDE_CRT_HOTPLUG_CPT(1  19)
 #define SDE_PORTD_HOTPLUG_CPT  (1  23)
 #define SDE_PORTC_HOTPLUG_CPT  (1  22)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7538f2e..7c91354 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -47,6 +47,8 @@
 
 #define wait_for(COND, MS) 

[PATCH 07/10 v2] drm/i915/intel_i2c: use WAIT cycle, not STOP

2012-03-10 Thread Daniel Kurtz
The i915 is only able to generate a STOP cycle (i.e. finalize an i2c
transaction) during a DATA or WAIT phase.  In other words, the
controller rejects a STOP requested as part of the first transaction in a
sequence.

Thus, for the first transaction we must always use a WAIT cycle, detect
when the device has finished (and is in a WAIT phase), and then either
start the next transaction, or, if there are no more transactions,
generate a STOP cycle.

Note: Theoretically, the last transaction of a multi-transaction sequence
could initiate a STOP cycle.  However, this slight optimization is left
for another patch.  We return -ETIMEDOUT if the hardware doesn't
deactivate after the STOP cycle.

This patch also takes advantage (in the write path) of the double-buffered
GMBUS3 data register by writing two 4-byte words before the first wait for
HW_RDY.

Signed-off-by: Daniel Kurtz djku...@chromium.org
---
 drivers/gpu/drm/i915/intel_i2c.c |   42 +
 1 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 151b828..b79a181 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -260,7 +260,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
if (msgs[i].flags  I2C_M_RD) {
I915_WRITE(GMBUS1 + reg_offset,
-  GMBUS_CYCLE_WAIT | (i + 1 == num ? 
GMBUS_CYCLE_STOP : 0) |
+  GMBUS_CYCLE_WAIT |
   (len  GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr  GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
@@ -272,7 +272,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
 (GMBUS_SATOER | GMBUS_HW_RDY),
 50))
goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset)  
GMBUS_SATOER)
+   if (I915_READ(GMBUS2 + reg_offset) 
+   GMBUS_SATOER)
goto clear_err;
 
val = I915_READ(GMBUS3 + reg_offset);
@@ -291,20 +292,13 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
I915_WRITE(GMBUS3 + reg_offset, val);
I915_WRITE(GMBUS1 + reg_offset,
-  (i + 1 == num ? GMBUS_CYCLE_STOP : 
GMBUS_CYCLE_WAIT) |
+  GMBUS_CYCLE_WAIT |
   (msgs[i].len  GMBUS_BYTE_COUNT_SHIFT) |
   (msgs[i].addr  GMBUS_SLAVE_ADDR_SHIFT) |
   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
POSTING_READ(GMBUS2 + reg_offset);
 
while (len) {
-   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
-(GMBUS_SATOER | GMBUS_HW_RDY),
-50))
-   goto timeout;
-   if (I915_READ(GMBUS2 + reg_offset)  
GMBUS_SATOER)
-   goto clear_err;
-
val = loop = 0;
do {
val |= *buf++  (8 * loop);
@@ -312,11 +306,18 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
I915_WRITE(GMBUS3 + reg_offset, val);
POSTING_READ(GMBUS2 + reg_offset);
+
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
+(GMBUS_SATOER | GMBUS_HW_RDY),
+50))
+   goto timeout;
+   if (I915_READ(GMBUS2 + reg_offset) 
+ GMBUS_SATOER)
+   goto clear_err;
}
}
 
-   if (i + 1  num 
-   wait_for(I915_READ(GMBUS2 + reg_offset) 
+   if (wait_for(I915_READ(GMBUS2 + reg_offset) 
 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
 50))
goto timeout;
@@ -344,9 +345,22 @@ clear_err:
ret = -ENXIO;
 
 done:
-   /* Mark the GMBUS interface as disabled. We will re-enable it at the
-* start of the next xfer, till then let it sleep.
+   if (I915_READ(GMBUS2 + reg_offset)  GMBUS_HW_WAIT_PHASE) {
+   I915_WRITE(GMBUS1 + reg_offset,
+  GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+   POSTING_READ(GMBUS2 + reg_offset);
+   }
+
+   /* Mark the GMBUS interface as disabled after 

[Bug 46796] [X800SE] Mouse cursor corruption when switching users

2012-03-10 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=46796

--- Comment #9 from jonathan jonathan.v...@gmail.com 2012-03-10 17:04:58 PST 
---
This patch causes my computer to crash at login. However, it's not a super bad
crash because I was able to ssh in and check dmesg. The comment did not appear.
Just to make sure it wasn't something I did when trying to compile a kernel, I
reversed the patch and recompiled, and I'm running that kernel now, so I'm
pretty sure it's the patch.

-- 
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
--- You are receiving this mail because: ---
You are the assignee for the bug.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch

2012-03-10 Thread Dave Airlie
On Sat, Mar 10, 2012 at 8:20 PM, Carsten Emde c.e...@osadl.org wrote:
 Some recent integrated graphics chipset, notably Intel's Pineview, also
 provide on-chip LVDS support. As an extra service, the LVDS interface supplies
 EDID data - irrespective of whether an LVDS panel is connected or not. The
 drm_mode_getresources() function, therefore, causes Xorg to always include
 the LVDS panel into the display and initialize a separate screen for it. e.g.
 (II) intel(0): Output LVDS1 connected
 (II) intel(0): Output VGA1 connected
 (II) intel(0): Using spanning desktop for initial modes
 (II) intel(0): Output LVDS1 using initial mode 1024x768 +0+0
 (II) intel(0): Output VGA1 using initial mode 1280x1024 +1024+0
 which is not what you want, if the only connected screen is a VGA monitor.
 One would assume that the BIOS settings of such systems would allow to
 separately enable or disable LVDS support; unfortunately, systems have been
 found in the wild that do not provide this feature.

So video=LVDS-1:d doesn't work for you?

Dave.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel