Hotplug¶
Simply put, hotplug occurs when a display is connected to or disconnected from the system. However, there may be adapters and docking stations and Display Port short pulses and MST devices involved, complicating matters.
Hotplug in i915 is handled in many different levels of abstraction.
The platform dependent interrupt handling code in i915_irq.c enables, disables, and does preliminary handling of the interrupts. The interrupt handlers gather the hotplug detect (HPD) information from relevant registers into a platform independent mask of hotplug pins that have fired.
The platform independent interrupt handler intel_hpd_irq_handler() in
intel_hotplug.c does hotplug irq storm detection and mitigation, and passes
further processing to appropriate bottom halves (Display Port specific and
regular hotplug).
The Display Port work function i915_digport_work_func() calls into
intel_dp_hpd_pulse() via hooks, which handles DP short pulses and DP MST long
pulses, with failures and non-MST long pulses triggering regular hotplug
processing on the connector.
The regular hotplug work function i915_hotplug_work_func() calls connector
detect hooks, and, if connector status changes, triggers sending of hotplug
uevent to userspace via drm_kms_helper_hotplug_event().
Finally, the userspace is responsible for triggering a modeset upon receiving the hotplug uevent, disabling or enabling the crtc as needed.
The hotplug interrupt storm detection and mitigation code keeps track of the number of interrupts per hotplug pin per a period of time, and if the number of interrupts exceeds a certain threshold, the interrupt is disabled for a while before being re-enabled. The intention is to mitigate issues raising from broken hardware triggering massive amounts of interrupts and grinding the system to a halt.
Current implementation expects that hotplug interrupt storm will not be seen when display port sink is connected, hence on platforms whose DP callback is handled by i915_digport_work_func reenabling of hpd is not performed (it was never expected to be disabled in the first place ;) ) this is specific to DP sinks handled by this routine and any other display such as HDMI or DVI enabled on the same port will have proper logic since it will use i915_hotplug_work_func where this logic is handled.
-
enum hpd_pin intel_hpd_pin_default(enum port port)¶
return default pin associated with certain port.
Parameters
enum port portthe hpd port to get associated pin
Description
It is only valid and used by digital port encoder.
Return pin that is associatade with port.
-
bool intel_hpd_irq_storm_detect(struct intel_display *display, enum hpd_pin pin, bool long_hpd)¶
gather stats and detect HPD IRQ storm on a pin
Parameters
struct intel_display *displaydisplay device
enum hpd_pin pinthe pin to gather stats on
bool long_hpdwhether the HPD IRQ was long or short
Description
Gather stats about HPD IRQs from the specified pin, and detect IRQ storms. Only the pin specific stats and state are changed, the caller is responsible for further action.
The number of IRQs that are allowed within HPD_STORM_DETECT_PERIOD is stored in display->hotplug.hpd_storm_threshold which defaults to HPD_STORM_DEFAULT_THRESHOLD. Long IRQs count as +10 to this threshold, and short IRQs count as +1. If this threshold is exceeded, it’s considered an IRQ storm and the IRQ state is set to HPD_MARK_DISABLED.
By default, most systems will only count long IRQs towards
display->hotplug.hpd_storm_threshold. However, some older systems also
suffer from short IRQ storms and must also track these. Because short IRQ
storms are naturally caused by sideband interactions with DP MST devices,
short IRQ detection is only enabled for systems without DP MST support.
Systems which are new enough to support DP MST are far less likely to
suffer from IRQ storms at all, so this is fine.
The HPD threshold can be controlled through i915_hpd_storm_ctl in debugfs, and should only be adjusted for automated hotplug testing.
Return true if an IRQ storm was detected on pin.
-
void intel_hpd_trigger_irq(struct intel_digital_port *dig_port)¶
trigger an hpd irq event for a port
Parameters
struct intel_digital_port *dig_portdigital port
Description
Trigger an HPD interrupt event for the given port, emulating a short pulse generated by the sink, and schedule the dig port work to handle it.
-
void intel_hpd_irq_handler(struct intel_display *display, u32 pin_mask, u32 long_mask)¶
main hotplug irq handler
Parameters
struct intel_display *displaydisplay device
u32 pin_maska mask of hpd pins that have triggered the irq
u32 long_maska mask of hpd pins that may be long hpd pulses
Description
This is the main hotplug irq handler for all platforms. The platform specific irq handlers call the platform specific hotplug irq handlers, which read and decode the appropriate registers into bitmasks about hpd pins that have triggered (pin_mask), and which of those pins may be long pulses (long_mask). The long_mask is ignored if the port corresponding to the pin is not a digital port.
Here, we do hotplug irq storm detection and mitigation, and pass further processing to appropriate bottom halves.
-
void intel_hpd_init(struct intel_display *display)¶
initializes and enables hpd support
Parameters
struct intel_display *displaydisplay device instance
Description
This function enables the hotplug support. It requires that interrupts have
already been enabled with intel_irq_init_hw(). From this point on hotplug and
poll request can run concurrently to other code, so locking rules must be
obeyed.
This is a separate step from interrupt enabling to simplify the locking rules in the driver load and resume code.
Also see: intel_hpd_poll_enable() and intel_hpd_poll_disable().
-
void intel_hpd_poll_enable(struct intel_display *display)¶
enable polling for connectors with hpd
Parameters
struct intel_display *displaydisplay device instance
Description
This function enables polling for all connectors which support HPD. Under certain conditions HPD may not be functional. On most Intel GPUs, this happens when we enter runtime suspend. On Valleyview and Cherryview systems, this also happens when we shut off all of the powerwells.
Since this function can get called in contexts where we’re already holding dev->mode_config.mutex, we do the actual hotplug enabling in a separate worker.
Also see: intel_hpd_init() and intel_hpd_poll_disable().
-
void intel_hpd_poll_disable(struct intel_display *display)¶
disable polling for connectors with hpd
Parameters
struct intel_display *displaydisplay device instance
Description
This function disables polling for all connectors which support HPD. Under certain conditions HPD may not be functional. On most Intel GPUs, this happens when we enter runtime suspend. On Valleyview and Cherryview systems, this also happens when we shut off all of the powerwells.
Since this function can get called in contexts where we’re already holding dev->mode_config.mutex, we do the actual hotplug enabling in a separate worker.
Also used during driver init to initialize connector->polled appropriately for all connectors.
Also see: intel_hpd_init() and intel_hpd_poll_enable().
-
void intel_hpd_block(struct intel_encoder *encoder)¶
Block handling of HPD IRQs on an HPD pin
Parameters
struct intel_encoder *encoderEncoder to block the HPD handling for
Description
Blocks the handling of HPD IRQs on the HPD pin of encoder.
On return:
It’s guaranteed that the blocked encoders’ HPD pulse handler (via intel_digital_port::
hpd_pulse()) is not running.The hotplug event handling (via intel_encoder::
hotplug()) of an HPD IRQ pending at the time this function is called may be still running.Detection on the encoder’s connector (via drm_connector_helper_funcs::
detect_ctx(), drm_connector_funcs::detect()) remains allowed, for instance as part of userspace connector probing, or DRM core’s connector polling.
The call must be followed by calling intel_hpd_unblock(), or
intel_hpd_clear_and_unblock().
Note that the handling of HPD IRQs for another encoder using the same HPD pin as that of encoder will be also blocked.
-
void intel_hpd_unblock(struct intel_encoder *encoder)¶
Unblock handling of HPD IRQs on an HPD pin
Parameters
struct intel_encoder *encoderEncoder to unblock the HPD handling for
Description
Unblock the handling of HPD IRQs on the HPD pin of encoder, which was
previously blocked by intel_hpd_block(). Any HPD IRQ raised on the
HPD pin while it was blocked will be handled for encoder and for any
other encoder sharing the same HPD pin.
-
void intel_hpd_clear_and_unblock(struct intel_encoder *encoder)¶
Unblock handling of new HPD IRQs on an HPD pin
Parameters
struct intel_encoder *encoderEncoder to unblock the HPD handling for
Description
Unblock the handling of HPD IRQs on the HPD pin of encoder, which was
previously blocked by intel_hpd_block(). Any HPD IRQ raised on the
HPD pin while it was blocked will be cleared, handling only new IRQs.