[Intel-gfx] [PATCH 6/7] drm/i915: abstract away platform specific parts from hpd handling

Jani Nikula jani.nikula at intel.com
Thu May 28 23:18:33 PDT 2015


On Thu, 28 May 2015, Paulo Zanoni <przanoni at gmail.com> wrote:
> 2015-05-28 9:43 GMT-03:00 Jani Nikula <jani.nikula at intel.com>:
>> Split intel_hpd_irq_handler into platforms specific and platform
>> agnostic parts. The platform specific parts decode the registers into
>> information about which hpd pins triggered, and if they were long
>> pulses. The platform agnostic parts do further processing, such as
>> interrupt storm mitigation and scheduling bottom halves.
>>
>> Signed-off-by: Jani Nikula <jani.nikula at intel.com>
>> ---
>>  drivers/gpu/drm/i915/i915_irq.c | 147 +++++++++++++++++++++++++++-------------
>>  1 file changed, 101 insertions(+), 46 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>> index 6fffbfd3121a..d401c863aeee 100644
>> --- a/drivers/gpu/drm/i915/i915_irq.c
>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>> @@ -1375,35 +1375,31 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
>>  #define HPD_STORM_DETECT_PERIOD 1000
>>  #define HPD_STORM_THRESHOLD 5
>>
>> -static int pch_port_to_hotplug_shift(enum port port)
>> +static bool pch_port_hotplug_long_detect(enum port port, u32 val)
>
> We could try to think on something better than just "val". IMHO all
> the variable names for the whole hotplug code on this file feel weird.
>
>
>>  {
>>         switch (port) {
>> -       case PORT_A:
>> -       case PORT_E:
>> -       default:
>> -               return -1;
>>         case PORT_B:
>> -               return 0;
>> +               return val & PORTB_HOTPLUG_LONG_DETECT;
>>         case PORT_C:
>> -               return 8;
>> +               return val & PORTC_HOTPLUG_LONG_DETECT;
>>         case PORT_D:
>> -               return 16;
>> +               return val & PORTD_HOTPLUG_LONG_DETECT;
>
> How about if we at least DRM_DEBUG_KMS() in case the short bit is not
> 1 for these "valid" ports? But I would prefer DRM_ERROR. This
> can/should be a separate patch.
>
>
>> +       default:
>> +               return false;
>>         }
>>  }
>>
>> -static int i915_port_to_hotplug_shift(enum port port)
>> +static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
>>  {
>>         switch (port) {
>> -       case PORT_A:
>> -       case PORT_E:
>> -       default:
>> -               return -1;
>>         case PORT_B:
>> -               return 17;
>> +               return val & PORTB_HOTPLUG_INT_LONG_PULSE;
>>         case PORT_C:
>> -               return 19;
>> +               return val & PORTC_HOTPLUG_INT_LONG_PULSE;
>>         case PORT_D:
>> -               return 21;
>> +               return val & PORTD_HOTPLUG_INT_LONG_PULSE;
>> +       default:
>> +               return false;
>>         }
>>  }
>>
>> @@ -1421,43 +1417,96 @@ static enum port get_port_from_pin(enum hpd_pin pin)
>>         }
>>  }
>>
>> +/* Get a bit mask of pins that have triggered, and which ones may be long. */
>> +static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
>> +                            u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS])
>
> <insert even louder complaints about going past 80 columns>
>
>> +{
>> +       int i;
>> +
>> +       *pin_mask = 0;
>> +       *long_mask = 0;
>> +
>> +       if (!hotplug_trigger)
>> +               return;
>> +
>> +       for_each_hpd_pin(i) {
>> +               if (hpd[i] & hotplug_trigger) {
>> +                       *pin_mask |= BIT(i);
>> +
>> +                       if (pch_port_hotplug_long_detect(get_port_from_pin(i), dig_hotplug_reg))
>> +                               *long_mask |= BIT(i);
>> +               }
>> +       }
>> +
>> +       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n",
>> +                        hotplug_trigger, dig_hotplug_reg, *pin_mask);
>> +
>> +}
>> +
>> +/* Get a bit mask of pins that have triggered, and which ones may be long. */
>> +static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
>> +                             u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS])
>> +{
>> +       int i;
>> +
>> +       *pin_mask = 0;
>> +       *long_mask = 0;
>> +
>> +       if (!hotplug_trigger)
>> +               return;
>> +
>> +       for_each_hpd_pin(i) {
>> +               if (hpd[i] & hotplug_trigger) {
>> +                       *pin_mask |= BIT(i);
>> +
>> +                       if (i9xx_port_hotplug_long_detect(get_port_from_pin(i), hotplug_trigger))
>> +                               *long_mask |= BIT(i);
>> +               }
>> +       }
>> +
>> +       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n",
>> +                        hotplug_trigger, *pin_mask);
>
> The fact that this is mostly duplicated code feels a little bit weird.
> I won't be surprised if some random person writes a patch to
> deduplicate this in the future. I could even give it a R-B.

I know, I was divided here myself. In the end I didn't want to make this
superficially platform independent with ifs inside, when the callers are
already platform specific. Also, the i9xx one does not have
dig_hotplug_reg, so not passing that in or logging adds clarity. But I
could have gone either way.

>
>
>> +}
>> +
>> +/**
>> + * intel_hpd_irq_handler - main hotplug irq handler
>> + * @dev: drm device
>> + * @pin_mask: a mask of hpd pins that have triggered the irq
>> + * @long_mask: a mask of hpd pins that may be long hpd pulses
>> + *
>> + * 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.
>
> Nice!
>
>> + *
>> + * Here, we do hotplug irq storm detection and mitigation, and pass further
>> + * processing to appropriate bottom halves.
>
> Now you can extract the code that does the storm detection and put it
> on its own function :)
> intel_hpd_storm_pin_update() or something else...

Yup, that's the plan, but things seem to move forward better with
smaller steps!

>
> Besides all the bikeshedding and suggestions for "part III", the code
> looks correct, and more organized, so with or without changes:
> Reviewed-by: Paulo Zanoni <paulo.r.zanoni at intel.com>

Thanks for the review and suggestions!

BR,
Jani.


>
>
>> + */
>>  static void intel_hpd_irq_handler(struct drm_device *dev,
>> -                                 u32 hotplug_trigger,
>> -                                 u32 dig_hotplug_reg,
>> -                                 const u32 hpd[HPD_NUM_PINS])
>> +                                 u32 pin_mask, u32 long_mask)
>>  {
>>         struct drm_i915_private *dev_priv = dev->dev_private;
>>         int i;
>>         enum port port;
>>         bool storm_detected = false;
>>         bool queue_dig = false, queue_hp = false;
>> -       u32 dig_shift;
>>         bool is_dig_port;
>>
>> -       if (!hotplug_trigger)
>> +       if (!pin_mask)
>>                 return;
>>
>> -       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x\n",
>> -                        hotplug_trigger, dig_hotplug_reg);
>> -
>>         spin_lock(&dev_priv->irq_lock);
>>         for_each_hpd_pin(i) {
>> -               if (!(hpd[i] & hotplug_trigger))
>> +               if (!(BIT(i) & pin_mask))
>>                         continue;
>>
>>                 port = get_port_from_pin(i);
>>                 is_dig_port = port && dev_priv->hotplug.irq_port[port];
>>
>>                 if (is_dig_port) {
>> -                       bool long_hpd;
>> -
>> -                       if (!HAS_GMCH_DISPLAY(dev_priv)) {
>> -                               dig_shift = pch_port_to_hotplug_shift(port);
>> -                               long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT;
>> -                       } else {
>> -                               dig_shift = i915_port_to_hotplug_shift(port);
>> -                               long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT;
>> -                       }
>> +                       bool long_hpd = long_mask & BIT(i);
>>
>>                         DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port),
>>                                          long_hpd ? "long" : "short");
>> @@ -1483,9 +1532,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev,
>>                          * interrupts on saner platforms.
>>                          */
>>                         WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev),
>> -                                 "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n",
>> -                                 hotplug_trigger, i, hpd[i]);
>> -
>> +                                 "Received HPD interrupt on pin %d although disabled\n", i);
>>                         continue;
>>                 }
>>
>> @@ -1493,7 +1540,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev,
>>                         continue;
>>
>>                 if (!is_dig_port) {
>> -                       dev_priv->hotplug.event_bits |= (1 << i);
>> +                       dev_priv->hotplug.event_bits |= BIT(i);
>>                         queue_hp = true;
>>                 }
>>
>> @@ -1505,7 +1552,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev,
>>                         DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i);
>>                 } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) {
>>                         dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED;
>> -                       dev_priv->hotplug.event_bits &= ~(1 << i);
>> +                       dev_priv->hotplug.event_bits &= ~BIT(i);
>>                         DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
>>                         storm_detected = true;
>>                 } else {
>> @@ -1753,6 +1800,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
>>  {
>>         struct drm_i915_private *dev_priv = dev->dev_private;
>>         u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
>> +       u32 pin_mask, long_mask;
>>
>>         if (!hotplug_status)
>>                 return;
>> @@ -1767,14 +1815,16 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
>>         if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
>>                 u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
>>
>> -               intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x);
>> +               i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x);
>> +               intel_hpd_irq_handler(dev, pin_mask, long_mask);
>>
>>                 if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
>>                         dp_aux_irq_handler(dev);
>>         } else {
>>                 u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
>>
>> -               intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915);
>> +               i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915);
>> +               intel_hpd_irq_handler(dev, pin_mask, long_mask);
>>         }
>>  }
>>
>> @@ -1874,11 +1924,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
>>         int pipe;
>>         u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
>>         u32 dig_hotplug_reg;
>> +       u32 pin_mask, long_mask;
>>
>>         dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
>>         I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
>>
>> -       intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_ibx);
>> +       pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_ibx);
>> +       intel_hpd_irq_handler(dev, pin_mask, long_mask);
>>
>>         if (pch_iir & SDE_AUDIO_POWER_MASK) {
>>                 int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
>> @@ -1971,11 +2023,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
>>         int pipe;
>>         u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
>>         u32 dig_hotplug_reg;
>> +       u32 pin_mask, long_mask;
>>
>>         dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
>>         I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
>>
>> -       intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_cpt);
>> +       pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_cpt);
>> +       intel_hpd_irq_handler(dev, pin_mask, long_mask);
>>
>>         if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
>>                 int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
>> @@ -2174,8 +2228,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>>  static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status)
>>  {
>>         struct drm_i915_private *dev_priv = dev->dev_private;
>> -       uint32_t hp_control;
>> -       uint32_t hp_trigger;
>> +       u32 hp_control, hp_trigger;
>> +       u32 pin_mask, long_mask;
>>
>>         /* Get the status */
>>         hp_trigger = iir_status & BXT_DE_PORT_HOTPLUG_MASK;
>> @@ -2191,7 +2245,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status)
>>                 hp_control & BXT_HOTPLUG_CTL_MASK);
>>
>>         /* Check for HPD storm and schedule bottom half */
>> -       intel_hpd_irq_handler(dev, hp_trigger, hp_control, hpd_bxt);
>> +       pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt);
>> +       intel_hpd_irq_handler(dev, pin_mask, long_mask);
>>
>>         /*
>>          * FIXME: Save the hot plug status for bottom half before
>> --
>> 2.1.4
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
>
>
> -- 
> Paulo Zanoni

-- 
Jani Nikula, Intel Open Source Technology Center


More information about the Intel-gfx mailing list