From: Ville Syrjala <ville.syrjala@linux.intel.com>
To: intel-gfx@lists.freedesktop.org
Cc: intel-xe@lists.freedesktop.org
Subject: [PATCH 1/3] drm/i915/gmbus: Switch GMBUS fully to _fw() register accesses
Date: Wed, 30 Sep 2026 14:53:01 +0300 [thread overview]
Message-ID: <20260930115303.24285-1-ville.syrjala@linux.intel.com> (raw)
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Switch the gmbus code over from _notrace() to _fw() register
accesses.
My original goal was just to eliminate the _notrace() variants
to shrink the intel_de.h API a bit, but while doing this I
stumbled on a huge performance issue with the current code;
Bit banging turns out to be extremely expensive on PCH
platforms while in DC5/6, and cause turns out not to be the
actual south GMBUS/GPIO register accesses, but rather the
extra north FPGA_DBG register access done from the non _fw()
register access functions. Those accesses cause a DC5/6 exit
which take a huge chunk of time.
$ time echo detect > /sys/class/drm/card0/HDMI-A-1/status
-real 0m16.281s
+real 0m1.459s
...
There does still seem to be a smallish (maybe ~15%) performance
penalty for accessing PCH registers while in DC5/6. Not really
sure what's causing it, but seems to be small enough to not cause
a huge performance problem for bit banging. When not in DC5/6
the same HDMI detect cycle takes ~1.25 seconds. If we want to
further speed that up we could completely disable DC5/6 during
big banged i2c transfers. Currently we only do that on BXT/GLK
because there the GMBUS hardware lives on the SoC and thus is
affected by DC states, even for non-bit banged transfers.
Note that by using the _fw() register accessors we also lose the
uncore.lock protection, but that's fine because everything is
already protected by the gmbus mutex, and nothing else should
live on the same cachelines of registers. So even platforms like
IVB/HSW which may have some issues with concurrent register
accesses to the same cacheline are still covered.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/display/intel_de.h | 6 ++++
drivers/gpu/drm/i915/display/intel_gmbus.c | 34 +++++++++++-----------
2 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h
index 102979019429..8144588d3cf7 100644
--- a/drivers/gpu/drm/i915/display/intel_de.h
+++ b/drivers/gpu/drm/i915/display/intel_de.h
@@ -158,6 +158,12 @@ intel_de_rmw_fw(struct intel_display *display, intel_reg_t reg, u32 clear, u32 s
return old;
}
+static inline void
+intel_de_posting_read_fw(struct intel_display *display, intel_reg_t reg)
+{
+ intel_de_read_fw(display, reg);
+}
+
static inline u32
intel_de_read_notrace(struct intel_display *display, intel_reg_t reg)
{
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index 60a70dea5d85..09171f3db298 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -218,8 +218,8 @@ to_intel_gmbus(struct i2c_adapter *i2c)
void
intel_gmbus_reset(struct intel_display *display)
{
- intel_de_write(display, GMBUS0(display), 0);
- intel_de_write(display, GMBUS4(display), 0);
+ intel_de_write_fw(display, GMBUS0(display), 0);
+ intel_de_write_fw(display, GMBUS4(display), 0);
}
static void pnv_gmbus_clock_gating(struct intel_display *display,
@@ -262,7 +262,7 @@ static u32 get_reserved(struct intel_gmbus *bus)
preserve_bits |= GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK |
GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK;
- return intel_de_read_notrace(display, bus->gpio_reg) & preserve_bits;
+ return intel_de_read_fw(display, bus->gpio_reg) & preserve_bits;
}
static int get_clock(void *data)
@@ -271,10 +271,10 @@ static int get_clock(void *data)
struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
- intel_de_write_notrace(display, bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
- intel_de_write_notrace(display, bus->gpio_reg, reserved);
+ intel_de_write_fw(display, bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
+ intel_de_write_fw(display, bus->gpio_reg, reserved);
- return (intel_de_read_notrace(display, bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
+ return (intel_de_read_fw(display, bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
}
static int get_data(void *data)
@@ -283,10 +283,10 @@ static int get_data(void *data)
struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
- intel_de_write_notrace(display, bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
- intel_de_write_notrace(display, bus->gpio_reg, reserved);
+ intel_de_write_fw(display, bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
+ intel_de_write_fw(display, bus->gpio_reg, reserved);
- return (intel_de_read_notrace(display, bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
+ return (intel_de_read_fw(display, bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
}
static void set_clock(void *data, int state_high)
@@ -302,8 +302,8 @@ static void set_clock(void *data, int state_high)
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK;
- intel_de_write_notrace(display, bus->gpio_reg, reserved | clock_bits);
- intel_de_posting_read(display, bus->gpio_reg);
+ intel_de_write_fw(display, bus->gpio_reg, reserved | clock_bits);
+ intel_de_posting_read_fw(display, bus->gpio_reg);
}
static void set_data(void *data, int state_high)
@@ -319,15 +319,15 @@ static void set_data(void *data, int state_high)
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK;
- intel_de_write_notrace(display, bus->gpio_reg, reserved | data_bits);
- intel_de_posting_read(display, bus->gpio_reg);
+ intel_de_write_fw(display, bus->gpio_reg, reserved | data_bits);
+ intel_de_posting_read_fw(display, bus->gpio_reg);
}
static void
ptl_handle_mask_bits(struct intel_gmbus *bus, bool set)
{
struct intel_display *display = bus->display;
- u32 reg_val = intel_de_read_notrace(display, bus->gpio_reg);
+ u32 reg_val = intel_de_read_fw(display, bus->gpio_reg);
u32 mask_bits = GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK |
GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK;
if (set)
@@ -335,8 +335,8 @@ ptl_handle_mask_bits(struct intel_gmbus *bus, bool set)
else
reg_val &= ~mask_bits;
- intel_de_write_notrace(display, bus->gpio_reg, reg_val);
- intel_de_posting_read(display, bus->gpio_reg);
+ intel_de_write_fw(display, bus->gpio_reg, reg_val);
+ intel_de_posting_read_fw(display, bus->gpio_reg);
}
static int
@@ -454,7 +454,7 @@ gmbus_wait_idle(struct intel_display *display)
add_wait_queue(&display->gmbus.wait_queue, &wait);
intel_de_write_fw(display, GMBUS4(display), irq_enable);
- ret = intel_de_wait_fw_ms(display, GMBUS2(display), GMBUS_ACTIVE, 0, 10, NULL);
+ ret = intel_de_wait_ms(display, GMBUS2(display), GMBUS_ACTIVE, 0, 10, NULL);
intel_de_write_fw(display, GMBUS4(display), 0);
remove_wait_queue(&display->gmbus.wait_queue, &wait);
--
2.54.0
next reply other threads:[~2026-09-30 11:53 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 11:53 Ville Syrjala [this message]
2026-09-30 11:53 ` [PATCH 2/3] drm/i915/dp: Drop using intel_de_read_notrace() Ville Syrjala
2026-09-30 12:02 ` sashiko-bot
2026-09-30 14:53 ` Jani Nikula
2026-10-01 15:16 ` Jani Nikula
2026-10-02 13:57 ` [PATCH v2 " Ville Syrjala
2026-09-30 11:53 ` [PATCH 3/3] drm/i915/de: Nuke intel_de_{read,write}_notrace() Ville Syrjala
2026-09-30 12:01 ` sashiko-bot
2026-09-30 14:54 ` Jani Nikula
2026-09-30 12:04 ` [PATCH 1/3] drm/i915/gmbus: Switch GMBUS fully to _fw() register accesses sashiko-bot
2026-09-30 13:16 ` [PATCH v2 " Ville Syrjala
2026-09-30 14:14 ` Jani Nikula
2026-09-30 13:52 ` ✓ i915.CI.BAT: success for series starting with [1/3] " Patchwork
2026-09-30 16:19 ` ✓ i915.CI.BAT: success for series starting with [v2,1/3] drm/i915/gmbus: Switch GMBUS fully to _fw() register accesses (rev2) Patchwork
2026-10-01 6:08 ` ✓ i915.CI.Full: " Patchwork
2026-10-02 16:18 ` ✗ i915.CI.BAT: failure for series starting with [v2,1/3] drm/i915/gmbus: Switch GMBUS fully to _fw() register accesses (rev3) Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260930115303.24285-1-ville.syrjala@linux.intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox