1a05eeebfSFrançois Tigeot /* 2a05eeebfSFrançois Tigeot * Copyright © 2015 Intel Corporation 3a05eeebfSFrançois Tigeot * 4a05eeebfSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 5a05eeebfSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 6a05eeebfSFrançois Tigeot * to deal in the Software without restriction, including without limitation 7a05eeebfSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8a05eeebfSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 9a05eeebfSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 10a05eeebfSFrançois Tigeot * 11a05eeebfSFrançois Tigeot * The above copyright notice and this permission notice (including the next 12a05eeebfSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 13a05eeebfSFrançois Tigeot * Software. 14a05eeebfSFrançois Tigeot * 15a05eeebfSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16a05eeebfSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17a05eeebfSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18a05eeebfSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19a05eeebfSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20a05eeebfSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21a05eeebfSFrançois Tigeot * IN THE SOFTWARE. 22a05eeebfSFrançois Tigeot */ 23a05eeebfSFrançois Tigeot 24a05eeebfSFrançois Tigeot #include <linux/kernel.h> 25a05eeebfSFrançois Tigeot 26a05eeebfSFrançois Tigeot #include <drm/drmP.h> 27a05eeebfSFrançois Tigeot #include <drm/i915_drm.h> 28a05eeebfSFrançois Tigeot 29a05eeebfSFrançois Tigeot #include "i915_drv.h" 30a05eeebfSFrançois Tigeot #include "intel_drv.h" 31a05eeebfSFrançois Tigeot 32a05eeebfSFrançois Tigeot /** 33a05eeebfSFrançois Tigeot * DOC: Hotplug 34a05eeebfSFrançois Tigeot * 35a05eeebfSFrançois Tigeot * Simply put, hotplug occurs when a display is connected to or disconnected 36a05eeebfSFrançois Tigeot * from the system. However, there may be adapters and docking stations and 37a05eeebfSFrançois Tigeot * Display Port short pulses and MST devices involved, complicating matters. 38a05eeebfSFrançois Tigeot * 39a05eeebfSFrançois Tigeot * Hotplug in i915 is handled in many different levels of abstraction. 40a05eeebfSFrançois Tigeot * 41a05eeebfSFrançois Tigeot * The platform dependent interrupt handling code in i915_irq.c enables, 42a05eeebfSFrançois Tigeot * disables, and does preliminary handling of the interrupts. The interrupt 43a05eeebfSFrançois Tigeot * handlers gather the hotplug detect (HPD) information from relevant registers 44a05eeebfSFrançois Tigeot * into a platform independent mask of hotplug pins that have fired. 45a05eeebfSFrançois Tigeot * 46a05eeebfSFrançois Tigeot * The platform independent interrupt handler intel_hpd_irq_handler() in 47a05eeebfSFrançois Tigeot * intel_hotplug.c does hotplug irq storm detection and mitigation, and passes 48a05eeebfSFrançois Tigeot * further processing to appropriate bottom halves (Display Port specific and 49a05eeebfSFrançois Tigeot * regular hotplug). 50a05eeebfSFrançois Tigeot * 51a05eeebfSFrançois Tigeot * The Display Port work function i915_digport_work_func() calls into 52a05eeebfSFrançois Tigeot * intel_dp_hpd_pulse() via hooks, which handles DP short pulses and DP MST long 53a05eeebfSFrançois Tigeot * pulses, with failures and non-MST long pulses triggering regular hotplug 54a05eeebfSFrançois Tigeot * processing on the connector. 55a05eeebfSFrançois Tigeot * 56a05eeebfSFrançois Tigeot * The regular hotplug work function i915_hotplug_work_func() calls connector 57a05eeebfSFrançois Tigeot * detect hooks, and, if connector status changes, triggers sending of hotplug 58a05eeebfSFrançois Tigeot * uevent to userspace via drm_kms_helper_hotplug_event(). 59a05eeebfSFrançois Tigeot * 60a05eeebfSFrançois Tigeot * Finally, the userspace is responsible for triggering a modeset upon receiving 61a05eeebfSFrançois Tigeot * the hotplug uevent, disabling or enabling the crtc as needed. 62a05eeebfSFrançois Tigeot * 63a05eeebfSFrançois Tigeot * The hotplug interrupt storm detection and mitigation code keeps track of the 64a05eeebfSFrançois Tigeot * number of interrupts per hotplug pin per a period of time, and if the number 65a05eeebfSFrançois Tigeot * of interrupts exceeds a certain threshold, the interrupt is disabled for a 66a05eeebfSFrançois Tigeot * while before being re-enabled. The intention is to mitigate issues raising 67a05eeebfSFrançois Tigeot * from broken hardware triggering massive amounts of interrupts and grinding 68a05eeebfSFrançois Tigeot * the system to a halt. 69a05eeebfSFrançois Tigeot * 70a05eeebfSFrançois Tigeot * Current implementation expects that hotplug interrupt storm will not be 71a05eeebfSFrançois Tigeot * seen when display port sink is connected, hence on platforms whose DP 72a05eeebfSFrançois Tigeot * callback is handled by i915_digport_work_func reenabling of hpd is not 73a05eeebfSFrançois Tigeot * performed (it was never expected to be disabled in the first place ;) ) 74a05eeebfSFrançois Tigeot * this is specific to DP sinks handled by this routine and any other display 75a05eeebfSFrançois Tigeot * such as HDMI or DVI enabled on the same port will have proper logic since 76a05eeebfSFrançois Tigeot * it will use i915_hotplug_work_func where this logic is handled. 77a05eeebfSFrançois Tigeot */ 78a05eeebfSFrançois Tigeot 79a05eeebfSFrançois Tigeot bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port) 80a05eeebfSFrançois Tigeot { 81a05eeebfSFrançois Tigeot switch (pin) { 82a05eeebfSFrançois Tigeot case HPD_PORT_A: 83a05eeebfSFrançois Tigeot *port = PORT_A; 84a05eeebfSFrançois Tigeot return true; 85a05eeebfSFrançois Tigeot case HPD_PORT_B: 86a05eeebfSFrançois Tigeot *port = PORT_B; 87a05eeebfSFrançois Tigeot return true; 88a05eeebfSFrançois Tigeot case HPD_PORT_C: 89a05eeebfSFrançois Tigeot *port = PORT_C; 90a05eeebfSFrançois Tigeot return true; 91a05eeebfSFrançois Tigeot case HPD_PORT_D: 92a05eeebfSFrançois Tigeot *port = PORT_D; 93a05eeebfSFrançois Tigeot return true; 94a05eeebfSFrançois Tigeot case HPD_PORT_E: 95a05eeebfSFrançois Tigeot *port = PORT_E; 96a05eeebfSFrançois Tigeot return true; 97a05eeebfSFrançois Tigeot default: 98a05eeebfSFrançois Tigeot return false; /* no hpd */ 99a05eeebfSFrançois Tigeot } 100a05eeebfSFrançois Tigeot } 101a05eeebfSFrançois Tigeot 102a05eeebfSFrançois Tigeot #define HPD_STORM_DETECT_PERIOD 1000 103a05eeebfSFrançois Tigeot #define HPD_STORM_THRESHOLD 5 104a05eeebfSFrançois Tigeot #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) 105a05eeebfSFrançois Tigeot 106a05eeebfSFrançois Tigeot /** 107a05eeebfSFrançois Tigeot * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin 108a05eeebfSFrançois Tigeot * @dev_priv: private driver data pointer 109a05eeebfSFrançois Tigeot * @pin: the pin to gather stats on 110a05eeebfSFrançois Tigeot * 111a05eeebfSFrançois Tigeot * Gather stats about HPD irqs from the specified @pin, and detect irq 112a05eeebfSFrançois Tigeot * storms. Only the pin specific stats and state are changed, the caller is 113a05eeebfSFrançois Tigeot * responsible for further action. 114a05eeebfSFrançois Tigeot * 115a05eeebfSFrançois Tigeot * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, 116a05eeebfSFrançois Tigeot * otherwise it's considered an irq storm, and the irq state is set to 117a05eeebfSFrançois Tigeot * @HPD_MARK_DISABLED. 118a05eeebfSFrançois Tigeot * 119a05eeebfSFrançois Tigeot * Return true if an irq storm was detected on @pin. 120a05eeebfSFrançois Tigeot */ 121a05eeebfSFrançois Tigeot static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, 122a05eeebfSFrançois Tigeot enum hpd_pin pin) 123a05eeebfSFrançois Tigeot { 124a05eeebfSFrançois Tigeot unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; 125a05eeebfSFrançois Tigeot unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); 126a05eeebfSFrançois Tigeot bool storm = false; 127a05eeebfSFrançois Tigeot 128a05eeebfSFrançois Tigeot if (!time_in_range(jiffies, start, end)) { 129a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].last_jiffies = jiffies; 130a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].count = 0; 131a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); 132a05eeebfSFrançois Tigeot } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { 133a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; 134a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); 135a05eeebfSFrançois Tigeot storm = true; 136a05eeebfSFrançois Tigeot } else { 137a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].count++; 138a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, 139a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].count); 140a05eeebfSFrançois Tigeot } 141a05eeebfSFrançois Tigeot 142a05eeebfSFrançois Tigeot return storm; 143a05eeebfSFrançois Tigeot } 144a05eeebfSFrançois Tigeot 145a05eeebfSFrançois Tigeot static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) 146a05eeebfSFrançois Tigeot { 147303bf270SFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 148a05eeebfSFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 149a05eeebfSFrançois Tigeot struct intel_connector *intel_connector; 150a05eeebfSFrançois Tigeot struct intel_encoder *intel_encoder; 151a05eeebfSFrançois Tigeot struct drm_connector *connector; 152a05eeebfSFrançois Tigeot enum hpd_pin pin; 153a05eeebfSFrançois Tigeot bool hpd_disabled = false; 154a05eeebfSFrançois Tigeot 155a05eeebfSFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 156a05eeebfSFrançois Tigeot 157a05eeebfSFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 158a05eeebfSFrançois Tigeot if (connector->polled != DRM_CONNECTOR_POLL_HPD) 159a05eeebfSFrançois Tigeot continue; 160a05eeebfSFrançois Tigeot 161a05eeebfSFrançois Tigeot intel_connector = to_intel_connector(connector); 162a05eeebfSFrançois Tigeot intel_encoder = intel_connector->encoder; 163a05eeebfSFrançois Tigeot if (!intel_encoder) 164a05eeebfSFrançois Tigeot continue; 165a05eeebfSFrançois Tigeot 166a05eeebfSFrançois Tigeot pin = intel_encoder->hpd_pin; 167a05eeebfSFrançois Tigeot if (pin == HPD_NONE || 168a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) 169a05eeebfSFrançois Tigeot continue; 170a05eeebfSFrançois Tigeot 171a05eeebfSFrançois Tigeot DRM_INFO("HPD interrupt storm detected on connector %s: " 172a05eeebfSFrançois Tigeot "switching from hotplug detection to polling\n", 173a05eeebfSFrançois Tigeot connector->name); 174a05eeebfSFrançois Tigeot 175a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[pin].state = HPD_DISABLED; 176a05eeebfSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_CONNECT 177a05eeebfSFrançois Tigeot | DRM_CONNECTOR_POLL_DISCONNECT; 178a05eeebfSFrançois Tigeot hpd_disabled = true; 179a05eeebfSFrançois Tigeot } 180a05eeebfSFrançois Tigeot 181a05eeebfSFrançois Tigeot /* Enable polling and queue hotplug re-enabling. */ 182a05eeebfSFrançois Tigeot if (hpd_disabled) { 183a05eeebfSFrançois Tigeot drm_kms_helper_poll_enable_locked(dev); 184a05eeebfSFrançois Tigeot mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, 185a05eeebfSFrançois Tigeot msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); 186a05eeebfSFrançois Tigeot } 187a05eeebfSFrançois Tigeot } 188a05eeebfSFrançois Tigeot 189a05eeebfSFrançois Tigeot static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) 190a05eeebfSFrançois Tigeot { 191a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = 192a05eeebfSFrançois Tigeot container_of(work, typeof(*dev_priv), 193a05eeebfSFrançois Tigeot hotplug.reenable_work.work); 194303bf270SFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 195a05eeebfSFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 196a05eeebfSFrançois Tigeot int i; 197a05eeebfSFrançois Tigeot 198a05eeebfSFrançois Tigeot intel_runtime_pm_get(dev_priv); 199a05eeebfSFrançois Tigeot 2005e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 201a05eeebfSFrançois Tigeot for_each_hpd_pin(i) { 202a05eeebfSFrançois Tigeot struct drm_connector *connector; 203a05eeebfSFrançois Tigeot 204a05eeebfSFrançois Tigeot if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) 205a05eeebfSFrançois Tigeot continue; 206a05eeebfSFrançois Tigeot 207a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[i].state = HPD_ENABLED; 208a05eeebfSFrançois Tigeot 209a05eeebfSFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 210a05eeebfSFrançois Tigeot struct intel_connector *intel_connector = to_intel_connector(connector); 211a05eeebfSFrançois Tigeot 212a05eeebfSFrançois Tigeot if (intel_connector->encoder->hpd_pin == i) { 213a05eeebfSFrançois Tigeot if (connector->polled != intel_connector->polled) 214a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", 215a05eeebfSFrançois Tigeot connector->name); 216a05eeebfSFrançois Tigeot connector->polled = intel_connector->polled; 217a05eeebfSFrançois Tigeot if (!connector->polled) 218a05eeebfSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 219a05eeebfSFrançois Tigeot } 220a05eeebfSFrançois Tigeot } 221a05eeebfSFrançois Tigeot } 222a05eeebfSFrançois Tigeot if (dev_priv->display.hpd_irq_setup) 2231487f786SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev_priv); 2245e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 225a05eeebfSFrançois Tigeot 226a05eeebfSFrançois Tigeot intel_runtime_pm_put(dev_priv); 227a05eeebfSFrançois Tigeot } 228a05eeebfSFrançois Tigeot 229a05eeebfSFrançois Tigeot static bool intel_hpd_irq_event(struct drm_device *dev, 230a05eeebfSFrançois Tigeot struct drm_connector *connector) 231a05eeebfSFrançois Tigeot { 232a05eeebfSFrançois Tigeot enum drm_connector_status old_status; 233a05eeebfSFrançois Tigeot 234a05eeebfSFrançois Tigeot WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 235a05eeebfSFrançois Tigeot old_status = connector->status; 236a05eeebfSFrançois Tigeot 237a05eeebfSFrançois Tigeot connector->status = connector->funcs->detect(connector, false); 238a05eeebfSFrançois Tigeot if (old_status == connector->status) 239a05eeebfSFrançois Tigeot return false; 240a05eeebfSFrançois Tigeot 241a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", 242a05eeebfSFrançois Tigeot connector->base.id, 243a05eeebfSFrançois Tigeot connector->name, 244a05eeebfSFrançois Tigeot drm_get_connector_status_name(old_status), 245a05eeebfSFrançois Tigeot drm_get_connector_status_name(connector->status)); 246a05eeebfSFrançois Tigeot 247a05eeebfSFrançois Tigeot return true; 248a05eeebfSFrançois Tigeot } 249a05eeebfSFrançois Tigeot 250a05eeebfSFrançois Tigeot static void i915_digport_work_func(struct work_struct *work) 251a05eeebfSFrançois Tigeot { 252a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = 253a05eeebfSFrançois Tigeot container_of(work, struct drm_i915_private, hotplug.dig_port_work); 254a05eeebfSFrançois Tigeot u32 long_port_mask, short_port_mask; 255a05eeebfSFrançois Tigeot struct intel_digital_port *intel_dig_port; 256a05eeebfSFrançois Tigeot int i; 257a05eeebfSFrançois Tigeot u32 old_bits = 0; 258a05eeebfSFrançois Tigeot 2595e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 260a05eeebfSFrançois Tigeot long_port_mask = dev_priv->hotplug.long_port_mask; 261a05eeebfSFrançois Tigeot dev_priv->hotplug.long_port_mask = 0; 262a05eeebfSFrançois Tigeot short_port_mask = dev_priv->hotplug.short_port_mask; 263a05eeebfSFrançois Tigeot dev_priv->hotplug.short_port_mask = 0; 2645e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 265a05eeebfSFrançois Tigeot 266a05eeebfSFrançois Tigeot for (i = 0; i < I915_MAX_PORTS; i++) { 267a05eeebfSFrançois Tigeot bool valid = false; 268a05eeebfSFrançois Tigeot bool long_hpd = false; 269a05eeebfSFrançois Tigeot intel_dig_port = dev_priv->hotplug.irq_port[i]; 270a05eeebfSFrançois Tigeot if (!intel_dig_port || !intel_dig_port->hpd_pulse) 271a05eeebfSFrançois Tigeot continue; 272a05eeebfSFrançois Tigeot 273a05eeebfSFrançois Tigeot if (long_port_mask & (1 << i)) { 274a05eeebfSFrançois Tigeot valid = true; 275a05eeebfSFrançois Tigeot long_hpd = true; 276a05eeebfSFrançois Tigeot } else if (short_port_mask & (1 << i)) 277a05eeebfSFrançois Tigeot valid = true; 278a05eeebfSFrançois Tigeot 279a05eeebfSFrançois Tigeot if (valid) { 280fae244afSFrançois Tigeot enum irqreturn ret; 281a05eeebfSFrançois Tigeot 282a05eeebfSFrançois Tigeot ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); 283fae244afSFrançois Tigeot if (ret == IRQ_NONE) { 284a05eeebfSFrançois Tigeot /* fall back to old school hpd */ 285a05eeebfSFrançois Tigeot old_bits |= (1 << intel_dig_port->base.hpd_pin); 286a05eeebfSFrançois Tigeot } 287a05eeebfSFrançois Tigeot } 288a05eeebfSFrançois Tigeot } 289a05eeebfSFrançois Tigeot 290a05eeebfSFrançois Tigeot if (old_bits) { 2915e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 292a05eeebfSFrançois Tigeot dev_priv->hotplug.event_bits |= old_bits; 2935e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 294a05eeebfSFrançois Tigeot schedule_work(&dev_priv->hotplug.hotplug_work); 295a05eeebfSFrançois Tigeot } 296a05eeebfSFrançois Tigeot } 297a05eeebfSFrançois Tigeot 298a05eeebfSFrançois Tigeot /* 299a05eeebfSFrançois Tigeot * Handle hotplug events outside the interrupt handler proper. 300a05eeebfSFrançois Tigeot */ 301a05eeebfSFrançois Tigeot static void i915_hotplug_work_func(struct work_struct *work) 302a05eeebfSFrançois Tigeot { 303a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = 304a05eeebfSFrançois Tigeot container_of(work, struct drm_i915_private, hotplug.hotplug_work); 305303bf270SFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 306a05eeebfSFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 307a05eeebfSFrançois Tigeot struct intel_connector *intel_connector; 308a05eeebfSFrançois Tigeot struct intel_encoder *intel_encoder; 309a05eeebfSFrançois Tigeot struct drm_connector *connector; 310a05eeebfSFrançois Tigeot bool changed = false; 311a05eeebfSFrançois Tigeot u32 hpd_event_bits; 312a05eeebfSFrançois Tigeot 313a05eeebfSFrançois Tigeot mutex_lock(&mode_config->mutex); 314a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("running encoder hotplug functions\n"); 315a05eeebfSFrançois Tigeot 3165e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 317a05eeebfSFrançois Tigeot 318a05eeebfSFrançois Tigeot hpd_event_bits = dev_priv->hotplug.event_bits; 319a05eeebfSFrançois Tigeot dev_priv->hotplug.event_bits = 0; 320a05eeebfSFrançois Tigeot 321a05eeebfSFrançois Tigeot /* Disable hotplug on connectors that hit an irq storm. */ 322a05eeebfSFrançois Tigeot intel_hpd_irq_storm_disable(dev_priv); 323a05eeebfSFrançois Tigeot 3245e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 325a05eeebfSFrançois Tigeot 326a05eeebfSFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 327a05eeebfSFrançois Tigeot intel_connector = to_intel_connector(connector); 328a05eeebfSFrançois Tigeot if (!intel_connector->encoder) 329a05eeebfSFrançois Tigeot continue; 330a05eeebfSFrançois Tigeot intel_encoder = intel_connector->encoder; 331a05eeebfSFrançois Tigeot if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { 332a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", 333a05eeebfSFrançois Tigeot connector->name, intel_encoder->hpd_pin); 334a05eeebfSFrançois Tigeot if (intel_encoder->hot_plug) 335a05eeebfSFrançois Tigeot intel_encoder->hot_plug(intel_encoder); 336a05eeebfSFrançois Tigeot if (intel_hpd_irq_event(dev, connector)) 337a05eeebfSFrançois Tigeot changed = true; 338a05eeebfSFrançois Tigeot } 339a05eeebfSFrançois Tigeot } 340a05eeebfSFrançois Tigeot mutex_unlock(&mode_config->mutex); 341a05eeebfSFrançois Tigeot 342a05eeebfSFrançois Tigeot if (changed) 343a05eeebfSFrançois Tigeot drm_kms_helper_hotplug_event(dev); 344a05eeebfSFrançois Tigeot } 345a05eeebfSFrançois Tigeot 3465e269720SFrançois Tigeot 347a05eeebfSFrançois Tigeot /** 348a05eeebfSFrançois Tigeot * intel_hpd_irq_handler - main hotplug irq handler 3491487f786SFrançois Tigeot * @dev_priv: drm_i915_private 350a05eeebfSFrançois Tigeot * @pin_mask: a mask of hpd pins that have triggered the irq 351a05eeebfSFrançois Tigeot * @long_mask: a mask of hpd pins that may be long hpd pulses 352a05eeebfSFrançois Tigeot * 353a05eeebfSFrançois Tigeot * This is the main hotplug irq handler for all platforms. The platform specific 354a05eeebfSFrançois Tigeot * irq handlers call the platform specific hotplug irq handlers, which read and 355a05eeebfSFrançois Tigeot * decode the appropriate registers into bitmasks about hpd pins that have 356a05eeebfSFrançois Tigeot * triggered (@pin_mask), and which of those pins may be long pulses 357a05eeebfSFrançois Tigeot * (@long_mask). The @long_mask is ignored if the port corresponding to the pin 358a05eeebfSFrançois Tigeot * is not a digital port. 359a05eeebfSFrançois Tigeot * 360a05eeebfSFrançois Tigeot * Here, we do hotplug irq storm detection and mitigation, and pass further 361a05eeebfSFrançois Tigeot * processing to appropriate bottom halves. 362a05eeebfSFrançois Tigeot */ 3631487f786SFrançois Tigeot void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, 364a05eeebfSFrançois Tigeot u32 pin_mask, u32 long_mask) 365a05eeebfSFrançois Tigeot { 366a05eeebfSFrançois Tigeot int i; 367a05eeebfSFrançois Tigeot enum port port; 368a05eeebfSFrançois Tigeot bool storm_detected = false; 369a05eeebfSFrançois Tigeot bool queue_dig = false, queue_hp = false; 370a05eeebfSFrançois Tigeot bool is_dig_port; 371a05eeebfSFrançois Tigeot 372a05eeebfSFrançois Tigeot if (!pin_mask) 373a05eeebfSFrançois Tigeot return; 374a05eeebfSFrançois Tigeot 375a05eeebfSFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 376a05eeebfSFrançois Tigeot for_each_hpd_pin(i) { 377a05eeebfSFrançois Tigeot if (!(BIT(i) & pin_mask)) 378a05eeebfSFrançois Tigeot continue; 379a05eeebfSFrançois Tigeot 380a05eeebfSFrançois Tigeot is_dig_port = intel_hpd_pin_to_port(i, &port) && 381a05eeebfSFrançois Tigeot dev_priv->hotplug.irq_port[port]; 382a05eeebfSFrançois Tigeot 383a05eeebfSFrançois Tigeot if (is_dig_port) { 384a05eeebfSFrançois Tigeot bool long_hpd = long_mask & BIT(i); 385a05eeebfSFrançois Tigeot 386a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), 387a05eeebfSFrançois Tigeot long_hpd ? "long" : "short"); 388a05eeebfSFrançois Tigeot /* 389a05eeebfSFrançois Tigeot * For long HPD pulses we want to have the digital queue happen, 390a05eeebfSFrançois Tigeot * but we still want HPD storm detection to function. 391a05eeebfSFrançois Tigeot */ 392a05eeebfSFrançois Tigeot queue_dig = true; 393a05eeebfSFrançois Tigeot if (long_hpd) { 394a05eeebfSFrançois Tigeot dev_priv->hotplug.long_port_mask |= (1 << port); 395a05eeebfSFrançois Tigeot } else { 396a05eeebfSFrançois Tigeot /* for short HPD just trigger the digital queue */ 397a05eeebfSFrançois Tigeot dev_priv->hotplug.short_port_mask |= (1 << port); 398a05eeebfSFrançois Tigeot continue; 399a05eeebfSFrançois Tigeot } 400a05eeebfSFrançois Tigeot } 401a05eeebfSFrançois Tigeot 402a05eeebfSFrançois Tigeot if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { 403a05eeebfSFrançois Tigeot /* 404a05eeebfSFrançois Tigeot * On GMCH platforms the interrupt mask bits only 405a05eeebfSFrançois Tigeot * prevent irq generation, not the setting of the 406a05eeebfSFrançois Tigeot * hotplug bits itself. So only WARN about unexpected 407a05eeebfSFrançois Tigeot * interrupts on saner platforms. 408a05eeebfSFrançois Tigeot */ 4091487f786SFrançois Tigeot WARN_ONCE(!HAS_GMCH_DISPLAY(dev_priv), 410a05eeebfSFrançois Tigeot "Received HPD interrupt on pin %d although disabled\n", i); 411a05eeebfSFrançois Tigeot continue; 412a05eeebfSFrançois Tigeot } 413a05eeebfSFrançois Tigeot 414a05eeebfSFrançois Tigeot if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) 415a05eeebfSFrançois Tigeot continue; 416a05eeebfSFrançois Tigeot 417a05eeebfSFrançois Tigeot if (!is_dig_port) { 418a05eeebfSFrançois Tigeot dev_priv->hotplug.event_bits |= BIT(i); 419a05eeebfSFrançois Tigeot queue_hp = true; 420a05eeebfSFrançois Tigeot } 421a05eeebfSFrançois Tigeot 422a05eeebfSFrançois Tigeot if (intel_hpd_irq_storm_detect(dev_priv, i)) { 423a05eeebfSFrançois Tigeot dev_priv->hotplug.event_bits &= ~BIT(i); 424a05eeebfSFrançois Tigeot storm_detected = true; 425a05eeebfSFrançois Tigeot } 426a05eeebfSFrançois Tigeot } 427a05eeebfSFrançois Tigeot 428a05eeebfSFrançois Tigeot if (storm_detected) 4291487f786SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev_priv); 430a05eeebfSFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 431a05eeebfSFrançois Tigeot 432a05eeebfSFrançois Tigeot /* 433a05eeebfSFrançois Tigeot * Our hotplug handler can grab modeset locks (by calling down into the 434a05eeebfSFrançois Tigeot * fb helpers). Hence it must not be run on our own dev-priv->wq work 435a05eeebfSFrançois Tigeot * queue for otherwise the flush_work in the pageflip code will 436a05eeebfSFrançois Tigeot * deadlock. 437a05eeebfSFrançois Tigeot */ 438a05eeebfSFrançois Tigeot if (queue_dig) 439a05eeebfSFrançois Tigeot queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); 440a05eeebfSFrançois Tigeot if (queue_hp) 441a05eeebfSFrançois Tigeot schedule_work(&dev_priv->hotplug.hotplug_work); 442a05eeebfSFrançois Tigeot } 443a05eeebfSFrançois Tigeot 444a05eeebfSFrançois Tigeot /** 445a05eeebfSFrançois Tigeot * intel_hpd_init - initializes and enables hpd support 446a05eeebfSFrançois Tigeot * @dev_priv: i915 device instance 447a05eeebfSFrançois Tigeot * 448a05eeebfSFrançois Tigeot * This function enables the hotplug support. It requires that interrupts have 449a05eeebfSFrançois Tigeot * already been enabled with intel_irq_init_hw(). From this point on hotplug and 450a05eeebfSFrançois Tigeot * poll request can run concurrently to other code, so locking rules must be 451a05eeebfSFrançois Tigeot * obeyed. 452a05eeebfSFrançois Tigeot * 453a05eeebfSFrançois Tigeot * This is a separate step from interrupt enabling to simplify the locking rules 454a05eeebfSFrançois Tigeot * in the driver load and resume code. 455bf017597SFrançois Tigeot * 456bf017597SFrançois Tigeot * Also see: intel_hpd_poll_init(), which enables connector polling 457a05eeebfSFrançois Tigeot */ 458a05eeebfSFrançois Tigeot void intel_hpd_init(struct drm_i915_private *dev_priv) 459a05eeebfSFrançois Tigeot { 460a05eeebfSFrançois Tigeot int i; 461a05eeebfSFrançois Tigeot 462a05eeebfSFrançois Tigeot for_each_hpd_pin(i) { 463a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[i].count = 0; 464a05eeebfSFrançois Tigeot dev_priv->hotplug.stats[i].state = HPD_ENABLED; 465a05eeebfSFrançois Tigeot } 466aee94f86SFrançois Tigeot 467bf017597SFrançois Tigeot WRITE_ONCE(dev_priv->hotplug.poll_enabled, false); 468bf017597SFrançois Tigeot schedule_work(&dev_priv->hotplug.poll_init_work); 4698621f407SFrançois Tigeot 4705e269720SFrançois Tigeot /* 4711487f786SFrançois Tigeot * Interrupt setup is already guaranteed to be single-threaded, this is 4721487f786SFrançois Tigeot * just to make the assert_spin_locked checks happy. 4735e269720SFrançois Tigeot */ 4741487f786SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 4751487f786SFrançois Tigeot if (dev_priv->display.hpd_irq_setup) 4761487f786SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev_priv); 4771487f786SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 478a05eeebfSFrançois Tigeot } 479a05eeebfSFrançois Tigeot 480*1e12ee3bSFrançois Tigeot static void i915_hpd_poll_init_work(struct work_struct *work) 481*1e12ee3bSFrançois Tigeot { 482bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = 483bf017597SFrançois Tigeot container_of(work, struct drm_i915_private, 484bf017597SFrançois Tigeot hotplug.poll_init_work); 485bf017597SFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 486bf017597SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 487bf017597SFrançois Tigeot struct drm_connector *connector; 488bf017597SFrançois Tigeot bool enabled; 489bf017597SFrançois Tigeot 490bf017597SFrançois Tigeot mutex_lock(&dev->mode_config.mutex); 491bf017597SFrançois Tigeot 492bf017597SFrançois Tigeot enabled = READ_ONCE(dev_priv->hotplug.poll_enabled); 493bf017597SFrançois Tigeot 494bf017597SFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 495bf017597SFrançois Tigeot struct intel_connector *intel_connector = 496bf017597SFrançois Tigeot to_intel_connector(connector); 497bf017597SFrançois Tigeot connector->polled = intel_connector->polled; 498bf017597SFrançois Tigeot 499bf017597SFrançois Tigeot /* MST has a dynamic intel_connector->encoder and it's reprobing 500bf017597SFrançois Tigeot * is all handled by the MST helpers. */ 501bf017597SFrançois Tigeot if (intel_connector->mst_port) 502bf017597SFrançois Tigeot continue; 503bf017597SFrançois Tigeot 504bf017597SFrançois Tigeot if (!connector->polled && I915_HAS_HOTPLUG(dev) && 505bf017597SFrançois Tigeot intel_connector->encoder->hpd_pin > HPD_NONE) { 506bf017597SFrançois Tigeot connector->polled = enabled ? 507bf017597SFrançois Tigeot DRM_CONNECTOR_POLL_CONNECT | 508bf017597SFrançois Tigeot DRM_CONNECTOR_POLL_DISCONNECT : 509bf017597SFrançois Tigeot DRM_CONNECTOR_POLL_HPD; 510bf017597SFrançois Tigeot } 511bf017597SFrançois Tigeot } 512bf017597SFrançois Tigeot 513bf017597SFrançois Tigeot if (enabled) 514bf017597SFrançois Tigeot drm_kms_helper_poll_enable_locked(dev); 515bf017597SFrançois Tigeot 516bf017597SFrançois Tigeot mutex_unlock(&dev->mode_config.mutex); 517bf017597SFrançois Tigeot 518bf017597SFrançois Tigeot /* 519bf017597SFrançois Tigeot * We might have missed any hotplugs that happened while we were 520bf017597SFrançois Tigeot * in the middle of disabling polling 521bf017597SFrançois Tigeot */ 522bf017597SFrançois Tigeot if (!enabled) 523bf017597SFrançois Tigeot drm_helper_hpd_irq_event(dev); 524bf017597SFrançois Tigeot } 525bf017597SFrançois Tigeot 526bf017597SFrançois Tigeot /** 527bf017597SFrançois Tigeot * intel_hpd_poll_init - enables/disables polling for connectors with hpd 528bf017597SFrançois Tigeot * @dev_priv: i915 device instance 529bf017597SFrançois Tigeot * 530bf017597SFrançois Tigeot * This function enables polling for all connectors, regardless of whether or 531bf017597SFrançois Tigeot * not they support hotplug detection. Under certain conditions HPD may not be 532bf017597SFrançois Tigeot * functional. On most Intel GPUs, this happens when we enter runtime suspend. 533bf017597SFrançois Tigeot * On Valleyview and Cherryview systems, this also happens when we shut off all 534bf017597SFrançois Tigeot * of the powerwells. 535bf017597SFrançois Tigeot * 536bf017597SFrançois Tigeot * Since this function can get called in contexts where we're already holding 537bf017597SFrançois Tigeot * dev->mode_config.mutex, we do the actual hotplug enabling in a seperate 538bf017597SFrançois Tigeot * worker. 539bf017597SFrançois Tigeot * 540bf017597SFrançois Tigeot * Also see: intel_hpd_init(), which restores hpd handling. 541bf017597SFrançois Tigeot */ 542bf017597SFrançois Tigeot void intel_hpd_poll_init(struct drm_i915_private *dev_priv) 543bf017597SFrançois Tigeot { 544bf017597SFrançois Tigeot WRITE_ONCE(dev_priv->hotplug.poll_enabled, true); 545bf017597SFrançois Tigeot 546bf017597SFrançois Tigeot /* 547bf017597SFrançois Tigeot * We might already be holding dev->mode_config.mutex, so do this in a 548bf017597SFrançois Tigeot * seperate worker 549bf017597SFrançois Tigeot * As well, there's no issue if we race here since we always reschedule 550bf017597SFrançois Tigeot * this worker anyway 551bf017597SFrançois Tigeot */ 552bf017597SFrançois Tigeot schedule_work(&dev_priv->hotplug.poll_init_work); 553bf017597SFrançois Tigeot } 554bf017597SFrançois Tigeot 555a05eeebfSFrançois Tigeot void intel_hpd_init_work(struct drm_i915_private *dev_priv) 556a05eeebfSFrançois Tigeot { 557a05eeebfSFrançois Tigeot INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); 558a05eeebfSFrançois Tigeot INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); 559bf017597SFrançois Tigeot INIT_WORK(&dev_priv->hotplug.poll_init_work, i915_hpd_poll_init_work); 560a05eeebfSFrançois Tigeot INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, 561a05eeebfSFrançois Tigeot intel_hpd_irq_storm_reenable_work); 562a05eeebfSFrançois Tigeot } 563a05eeebfSFrançois Tigeot 564a05eeebfSFrançois Tigeot void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) 565a05eeebfSFrançois Tigeot { 5665e269720SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 567a05eeebfSFrançois Tigeot 568a05eeebfSFrançois Tigeot dev_priv->hotplug.long_port_mask = 0; 569a05eeebfSFrançois Tigeot dev_priv->hotplug.short_port_mask = 0; 570a05eeebfSFrançois Tigeot dev_priv->hotplug.event_bits = 0; 571a05eeebfSFrançois Tigeot 5725e269720SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 573a05eeebfSFrançois Tigeot 574a05eeebfSFrançois Tigeot cancel_work_sync(&dev_priv->hotplug.dig_port_work); 575a05eeebfSFrançois Tigeot cancel_work_sync(&dev_priv->hotplug.hotplug_work); 576bf017597SFrançois Tigeot cancel_work_sync(&dev_priv->hotplug.poll_init_work); 577a05eeebfSFrançois Tigeot cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); 578a05eeebfSFrançois Tigeot } 579bf017597SFrançois Tigeot 580bf017597SFrançois Tigeot bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin) 581bf017597SFrançois Tigeot { 582bf017597SFrançois Tigeot bool ret = false; 583bf017597SFrançois Tigeot 584bf017597SFrançois Tigeot if (pin == HPD_NONE) 585bf017597SFrançois Tigeot return false; 586bf017597SFrançois Tigeot 587bf017597SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 588bf017597SFrançois Tigeot if (dev_priv->hotplug.stats[pin].state == HPD_ENABLED) { 589bf017597SFrançois Tigeot dev_priv->hotplug.stats[pin].state = HPD_DISABLED; 590bf017597SFrançois Tigeot ret = true; 591bf017597SFrançois Tigeot } 592bf017597SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 593bf017597SFrançois Tigeot 594bf017597SFrançois Tigeot return ret; 595bf017597SFrançois Tigeot } 596bf017597SFrançois Tigeot 597bf017597SFrançois Tigeot void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin) 598bf017597SFrançois Tigeot { 599bf017597SFrançois Tigeot if (pin == HPD_NONE) 600bf017597SFrançois Tigeot return; 601bf017597SFrançois Tigeot 602bf017597SFrançois Tigeot spin_lock_irq(&dev_priv->irq_lock); 603bf017597SFrançois Tigeot dev_priv->hotplug.stats[pin].state = HPD_ENABLED; 604bf017597SFrançois Tigeot spin_unlock_irq(&dev_priv->irq_lock); 605bf017597SFrançois Tigeot } 606