Skip to content

Commit c19f5a0

Browse files
committed
drm/i915: Hook up display fault interrupts for VLV/CHV
Hook up the display fault irq handlers for VLV/CHV. Unfortunately the actual hardware doesn't agree with the spec on how DPINVGTT should behave. The docs claim that the status bits can be cleared by writing '1' to them, but in reality there doesn't seem to be any way to clear them. So we must disable and ignore any fault we've already seen in the past. The entire register does reset when the display power well goes down, so we can just always re-enable all the bits in irq postinstall without having to track the state beyond that. v2: Use intel_display instead of dev_priv Move xe gen2_error_{init,reset}() out Reviewed-by: Vinod Govindapillai <vinod.govindapillai@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20250217070047.953-9-ville.syrjala@linux.intel.com
1 parent b6cfae8 commit c19f5a0

File tree

4 files changed

+158
-1
lines changed

4 files changed

+158
-1
lines changed

drivers/gpu/drm/i915/display/intel_display_irq.c

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,114 @@ void bdw_disable_vblank(struct drm_crtc *_crtc)
17841784
schedule_work(&display->irq.vblank_dc_work);
17851785
}
17861786

1787+
static u32 vlv_dpinvgtt_pipe_fault_mask(enum pipe pipe)
1788+
{
1789+
switch (pipe) {
1790+
case PIPE_A:
1791+
return SPRITEB_INVALID_GTT_STATUS |
1792+
SPRITEA_INVALID_GTT_STATUS |
1793+
PLANEA_INVALID_GTT_STATUS |
1794+
CURSORA_INVALID_GTT_STATUS;
1795+
case PIPE_B:
1796+
return SPRITED_INVALID_GTT_STATUS |
1797+
SPRITEC_INVALID_GTT_STATUS |
1798+
PLANEB_INVALID_GTT_STATUS |
1799+
CURSORB_INVALID_GTT_STATUS;
1800+
case PIPE_C:
1801+
return SPRITEF_INVALID_GTT_STATUS |
1802+
SPRITEE_INVALID_GTT_STATUS |
1803+
PLANEC_INVALID_GTT_STATUS |
1804+
CURSORC_INVALID_GTT_STATUS;
1805+
default:
1806+
return 0;
1807+
}
1808+
}
1809+
1810+
static const struct pipe_fault_handler vlv_pipe_fault_handlers[] = {
1811+
{ .fault = SPRITEB_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE1, },
1812+
{ .fault = SPRITEA_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE0, },
1813+
{ .fault = PLANEA_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_PRIMARY, },
1814+
{ .fault = CURSORA_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_CURSOR, },
1815+
{ .fault = SPRITED_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE1, },
1816+
{ .fault = SPRITEC_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE0, },
1817+
{ .fault = PLANEB_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_PRIMARY, },
1818+
{ .fault = CURSORB_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_CURSOR, },
1819+
{ .fault = SPRITEF_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE1, },
1820+
{ .fault = SPRITEE_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_SPRITE0, },
1821+
{ .fault = PLANEC_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_PRIMARY, },
1822+
{ .fault = CURSORC_INVALID_GTT_STATUS, .handle = handle_plane_fault, .plane_id = PLANE_CURSOR, },
1823+
{}
1824+
};
1825+
1826+
static void vlv_page_table_error_irq_ack(struct intel_display *display, u32 *dpinvgtt)
1827+
{
1828+
u32 status, enable, tmp;
1829+
1830+
tmp = intel_de_read(display, DPINVGTT);
1831+
1832+
enable = tmp >> 16;
1833+
status = tmp & 0xffff;
1834+
1835+
/*
1836+
* Despite what the docs claim, the status bits seem to get
1837+
* stuck permanently (similar the old PGTBL_ER register), so
1838+
* we have to disable and ignore them once set. They do get
1839+
* reset if the display power well goes down, so no need to
1840+
* track the enable mask explicitly.
1841+
*/
1842+
*dpinvgtt = status & enable;
1843+
enable &= ~status;
1844+
1845+
/* customary ack+disable then re-enable to guarantee an edge */
1846+
intel_de_write(display, DPINVGTT, status);
1847+
intel_de_write(display, DPINVGTT, enable << 16);
1848+
}
1849+
1850+
static void vlv_page_table_error_irq_handler(struct intel_display *display, u32 dpinvgtt)
1851+
{
1852+
enum pipe pipe;
1853+
1854+
for_each_pipe(display, pipe) {
1855+
u32 fault_errors;
1856+
1857+
fault_errors = dpinvgtt & vlv_dpinvgtt_pipe_fault_mask(pipe);
1858+
if (fault_errors)
1859+
intel_pipe_fault_irq_handler(display, vlv_pipe_fault_handlers,
1860+
pipe, fault_errors);
1861+
}
1862+
}
1863+
1864+
void vlv_display_error_irq_ack(struct intel_display *display,
1865+
u32 *eir, u32 *dpinvgtt)
1866+
{
1867+
u32 emr;
1868+
1869+
*eir = intel_de_read(display, VLV_EIR);
1870+
1871+
if (*eir & VLV_ERROR_PAGE_TABLE)
1872+
vlv_page_table_error_irq_ack(display, dpinvgtt);
1873+
1874+
intel_de_write(display, VLV_EIR, *eir);
1875+
1876+
/*
1877+
* Toggle all EMR bits to make sure we get an edge
1878+
* in the ISR master error bit if we don't clear
1879+
* all the EIR bits.
1880+
*/
1881+
emr = intel_de_read(display, VLV_EMR);
1882+
intel_de_write(display, VLV_EMR, 0xffffffff);
1883+
intel_de_write(display, VLV_EMR, emr);
1884+
}
1885+
1886+
void vlv_display_error_irq_handler(struct intel_display *display,
1887+
u32 eir, u32 dpinvgtt)
1888+
{
1889+
drm_dbg(display->drm, "Master Error, EIR 0x%08x\n", eir);
1890+
1891+
if (eir & VLV_ERROR_PAGE_TABLE)
1892+
vlv_page_table_error_irq_handler(display, dpinvgtt);
1893+
}
1894+
17871895
static void _vlv_display_irq_reset(struct drm_i915_private *dev_priv)
17881896
{
17891897
struct intel_display *display = &dev_priv->display;
@@ -1793,6 +1901,9 @@ static void _vlv_display_irq_reset(struct drm_i915_private *dev_priv)
17931901
else
17941902
intel_de_write(display, DPINVGTT, DPINVGTT_STATUS_MASK_VLV);
17951903

1904+
gen2_error_reset(to_intel_uncore(display->drm),
1905+
VLV_ERROR_REGS);
1906+
17961907
i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
17971908
intel_de_rmw(display, PORT_HOTPLUG_STAT(dev_priv), 0, 0);
17981909

@@ -1820,6 +1931,12 @@ void i9xx_display_irq_reset(struct drm_i915_private *i915)
18201931
i9xx_pipestat_irq_reset(i915);
18211932
}
18221933

1934+
static u32 vlv_error_mask(void)
1935+
{
1936+
/* TODO enable other errors too? */
1937+
return VLV_ERROR_PAGE_TABLE;
1938+
}
1939+
18231940
void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
18241941
{
18251942
struct intel_display *display = &dev_priv->display;
@@ -1830,6 +1947,18 @@ void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
18301947
if (!dev_priv->display.irq.vlv_display_irqs_enabled)
18311948
return;
18321949

1950+
if (IS_CHERRYVIEW(dev_priv))
1951+
intel_de_write(display, DPINVGTT,
1952+
DPINVGTT_STATUS_MASK_CHV |
1953+
DPINVGTT_EN_MASK_CHV);
1954+
else
1955+
intel_de_write(display, DPINVGTT,
1956+
DPINVGTT_STATUS_MASK_VLV |
1957+
DPINVGTT_EN_MASK_VLV);
1958+
1959+
gen2_error_init(to_intel_uncore(display->drm),
1960+
VLV_ERROR_REGS, ~vlv_error_mask());
1961+
18331962
pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
18341963

18351964
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
@@ -1840,7 +1969,8 @@ void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
18401969
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
18411970
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
18421971
I915_LPE_PIPE_A_INTERRUPT |
1843-
I915_LPE_PIPE_B_INTERRUPT;
1972+
I915_LPE_PIPE_B_INTERRUPT |
1973+
I915_MASTER_ERROR_INTERRUPT;
18441974

18451975
if (IS_CHERRYVIEW(dev_priv))
18461976
enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |

drivers/gpu/drm/i915/display/intel_display_irq.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ void i915_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_
7676
void i965_pipestat_irq_handler(struct drm_i915_private *i915, u32 iir, u32 pipe_stats[I915_MAX_PIPES]);
7777
void valleyview_pipestat_irq_handler(struct drm_i915_private *i915, u32 pipe_stats[I915_MAX_PIPES]);
7878

79+
void vlv_display_error_irq_ack(struct intel_display *display, u32 *eir, u32 *dpinvgtt);
80+
void vlv_display_error_irq_handler(struct intel_display *display, u32 eir, u32 dpinvgtt);
81+
7982
void intel_display_irq_init(struct drm_i915_private *i915);
8083

8184
void i915gm_irq_cstate_wa(struct drm_i915_private *i915, bool enable);

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
241241

242242
do {
243243
u32 iir, gt_iir, pm_iir;
244+
u32 eir = 0, dpinvgtt = 0;
244245
u32 pipe_stats[I915_MAX_PIPES] = {};
245246
u32 hotplug_status = 0;
246247
u32 ier = 0;
@@ -278,6 +279,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
278279
if (iir & I915_DISPLAY_PORT_INTERRUPT)
279280
hotplug_status = i9xx_hpd_irq_ack(dev_priv);
280281

282+
if (iir & I915_MASTER_ERROR_INTERRUPT)
283+
vlv_display_error_irq_ack(display, &eir, &dpinvgtt);
284+
281285
/* Call regardless, as some status bits might not be
282286
* signalled in IIR */
283287
i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
@@ -304,6 +308,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
304308
if (hotplug_status)
305309
i9xx_hpd_irq_handler(dev_priv, hotplug_status);
306310

311+
if (iir & I915_MASTER_ERROR_INTERRUPT)
312+
vlv_display_error_irq_handler(display, eir, dpinvgtt);
313+
307314
valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
308315
} while (0);
309316

@@ -328,6 +335,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
328335

329336
do {
330337
u32 master_ctl, iir;
338+
u32 eir = 0, dpinvgtt = 0;
331339
u32 pipe_stats[I915_MAX_PIPES] = {};
332340
u32 hotplug_status = 0;
333341
u32 ier = 0;
@@ -361,6 +369,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
361369
if (iir & I915_DISPLAY_PORT_INTERRUPT)
362370
hotplug_status = i9xx_hpd_irq_ack(dev_priv);
363371

372+
if (iir & I915_MASTER_ERROR_INTERRUPT)
373+
vlv_display_error_irq_ack(display, &eir, &dpinvgtt);
374+
364375
/* Call regardless, as some status bits might not be
365376
* signalled in IIR */
366377
i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
@@ -383,6 +394,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
383394
if (hotplug_status)
384395
i9xx_hpd_irq_handler(dev_priv, hotplug_status);
385396

397+
if (iir & I915_MASTER_ERROR_INTERRUPT)
398+
vlv_display_error_irq_handler(display, eir, dpinvgtt);
399+
386400
valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
387401
} while (0);
388402

drivers/gpu/drm/i915/i915_reg.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,16 @@
475475

476476
#define GEN2_ERROR_REGS I915_ERROR_REGS(EMR, EIR)
477477

478+
#define VLV_EIR _MMIO(VLV_DISPLAY_BASE + 0x20b0)
479+
#define VLV_EMR _MMIO(VLV_DISPLAY_BASE + 0x20b4)
480+
#define VLV_ESR _MMIO(VLV_DISPLAY_BASE + 0x20b8)
481+
#define VLV_ERROR_GUNIT_TLB_DATA (1 << 6)
482+
#define VLV_ERROR_GUNIT_TLB_PTE (1 << 5)
483+
#define VLV_ERROR_PAGE_TABLE (1 << 4)
484+
#define VLV_ERROR_CLAIM (1 << 0)
485+
486+
#define VLV_ERROR_REGS I915_ERROR_REGS(VLV_EMR, VLV_EIR)
487+
478488
#define INSTPM _MMIO(0x20c0)
479489
#define INSTPM_SELF_EN (1 << 12) /* 915GM only */
480490
#define INSTPM_AGPBUSY_INT_EN (1 << 11) /* gen3: when disabled, pending interrupts

0 commit comments

Comments
 (0)