[PATCH 1/2] drm/msm/dp: Clean up handling of DP AUX interrupts
Kuogee Hsieh
quic_khsieh at quicinc.com
Wed Jan 25 17:13:27 UTC 2023
On 1/19/2023 2:53 PM, Douglas Anderson wrote:
> The DP AUX interrupt handling was a bit of a mess.
> * There were two functions (one for "native" transfers and one for
> "i2c" transfers) that were quite similar. It was hard to say how
> many of the differences between the two functions were on purpose
> and how many of them were just an accident of how they were coded.
> * Each function sometimes used "else if" to test for error bits and
> sometimes didn't and again it was hard to say if this was on purpose
> or just an accident.
> * The two functions wouldn't notice whether "unknown" bits were
> set. For instance, there seems to be a bit "DP_INTR_PLL_UNLOCKED"
> and if it was set there would be no indication.
> * The two functions wouldn't notice if more than one error was set.
>
> Let's fix this by being more consistent / explicit about what we're
> doing.
>
> By design this could cause different handling for AUX transfers,
> though I'm not actually aware of any bug fixed as a result of
> this patch (this patch was created because we simply noticed how odd
> the old code was by code inspection). Specific notes here:
> 1. In the old native transfer case if we got "done + wrong address"
> we'd ignore the "wrong address" (because of the "else if"). Now we
> won't.
> 2. In the old native transfer case if we got "done + timeout" we'd
> ignore the "timeout" (because of the "else if"). Now we won't.
> 3. In the old native transfer case we'd see "nack_defer" and translate
> it to the error number for "nack". This differed from the i2c
> transfer case where "nack_defer" was given the error number for
> "nack_defer". This 100% can't matter because the only user of this
> error number treats "nack defer" the same as "nack", so it's clear
> that the difference between the "native" and "i2c" was pointless
> here.
> 4. In the old i2c transfer case if we got "done" plus any error
> besides "nack" or "defer" then we'd ignore the error. Now we don't.
> 5. If there is more than one error signaled by the hardware it's
> possible that we'll report a different one than we used to. I don't
> know if this matters. If someone is aware of a case this matters we
> should document it and change the code to make it explicit.
> 6. One quirk we keep (I don't know if this is important) is that in
> the i2c transfer case if we see "done + defer" we report that as a
> "nack". That seemed too intentional in the old code to just drop.
>
> After this change we will add extra logging, including:
> * A warning if we see more than one error bit set.
> * A warning if we see an unexpected interrupt.
> * A warning if we get an AUX transfer interrupt when shouldn't.
>
> It actually turns out that as a result of this change then at boot we
> sometimes see an error:
> [drm:dp_aux_isr] *ERROR* Unexpected DP AUX IRQ 0x01000000 when not busy
> That means that, during init, we are seeing DP_INTR_PLL_UNLOCKED. For
> now I'm going to say that leaving this error reported in the logs is
> OK-ish and hopefully it will encourage someone to track down what's
> going on at init time.
>
> One last note here is that this change renames one of the interrupt
> bits. The bit named "i2c done" clearly was used for native transfers
> being done too, so I renamed it to indicate this.
>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
> I don't have good test coverage for this change and it does have the
> potential to change behavior. I confirmed that eDP and DP still
> continue to work OK on one machine. Hopefully folks can test it more.
>
> drivers/gpu/drm/msm/dp/dp_aux.c | 80 ++++++++++++-----------------
> drivers/gpu/drm/msm/dp/dp_catalog.c | 2 +-
> drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
> 3 files changed, 36 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
> index cc3efed593aa..34ad08ae6eb9 100644
> --- a/drivers/gpu/drm/msm/dp/dp_aux.c
> +++ b/drivers/gpu/drm/msm/dp/dp_aux.c
> @@ -162,47 +162,6 @@ static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
> return i;
> }
>
> -static void dp_aux_native_handler(struct dp_aux_private *aux, u32 isr)
> -{
> - if (isr & DP_INTR_AUX_I2C_DONE)
> - aux->aux_error_num = DP_AUX_ERR_NONE;
> - else if (isr & DP_INTR_WRONG_ADDR)
> - aux->aux_error_num = DP_AUX_ERR_ADDR;
> - else if (isr & DP_INTR_TIMEOUT)
> - aux->aux_error_num = DP_AUX_ERR_TOUT;
> - if (isr & DP_INTR_NACK_DEFER)
> - aux->aux_error_num = DP_AUX_ERR_NACK;
> - if (isr & DP_INTR_AUX_ERROR) {
> - aux->aux_error_num = DP_AUX_ERR_PHY;
> - dp_catalog_aux_clear_hw_interrupts(aux->catalog);
> - }
> -}
> -
> -static void dp_aux_i2c_handler(struct dp_aux_private *aux, u32 isr)
> -{
> - if (isr & DP_INTR_AUX_I2C_DONE) {
> - if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
> - aux->aux_error_num = DP_AUX_ERR_NACK;
> - else
> - aux->aux_error_num = DP_AUX_ERR_NONE;
> - } else {
> - if (isr & DP_INTR_WRONG_ADDR)
> - aux->aux_error_num = DP_AUX_ERR_ADDR;
> - else if (isr & DP_INTR_TIMEOUT)
> - aux->aux_error_num = DP_AUX_ERR_TOUT;
> - if (isr & DP_INTR_NACK_DEFER)
> - aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
> - if (isr & DP_INTR_I2C_NACK)
> - aux->aux_error_num = DP_AUX_ERR_NACK;
> - if (isr & DP_INTR_I2C_DEFER)
> - aux->aux_error_num = DP_AUX_ERR_DEFER;
> - if (isr & DP_INTR_AUX_ERROR) {
> - aux->aux_error_num = DP_AUX_ERR_PHY;
> - dp_catalog_aux_clear_hw_interrupts(aux->catalog);
> - }
> - }
> -}
> -
> static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
> struct drm_dp_aux_msg *input_msg)
> {
> @@ -427,13 +386,42 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux)
> if (!isr)
> return;
>
> - if (!aux->cmd_busy)
> + if (!aux->cmd_busy) {
> + DRM_ERROR("Unexpected DP AUX IRQ %#010x when not busy\n", isr);
> return;
> + }
>
> - if (aux->native)
> - dp_aux_native_handler(aux, isr);
> - else
> - dp_aux_i2c_handler(aux, isr);
> + /*
> + * The logic below assumes only one error bit is set (other than "done"
> + * which can apparently be set at the same time as some of the other
> + * bits). Warn if more than one get set so we know we need to improve
> + * the logic.
> + */
> + if (hweight32(isr & ~DP_INTR_AUX_XFER_DONE) > 1)
> + DRM_WARN("Some DP AUX interrupts unhandled: %#010x\n", isr);
> +
> + if (isr & DP_INTR_AUX_ERROR) {
> + aux->aux_error_num = DP_AUX_ERR_PHY;
> + dp_catalog_aux_clear_hw_interrupts(aux->catalog);
> + } else if (isr & DP_INTR_NACK_DEFER) {
> + aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
> + } else if (isr & DP_INTR_WRONG_ADDR) {
> + aux->aux_error_num = DP_AUX_ERR_ADDR;
> + } else if (isr & DP_INTR_TIMEOUT) {
> + aux->aux_error_num = DP_AUX_ERR_TOUT;
> + } else if (isr & DP_INTR_AUX_XFER_DONE) {
> + aux->aux_error_num = DP_AUX_ERR_NONE;
1) both DP_INTR_AUX_XFER_DONE and DP_INTR_I2C_NACK are set
2) both DP_INTR_AUX_XFER_DONE and DP_INTR_I2C_DEFER are set
with above two condition, below two "else if" will not be reached since
DP_INTR_AUX_XFER_DONE is check with higher priority
> + } else if (!aux->native && (isr & DP_INTR_I2C_NACK)) {
> + aux->aux_error_num = DP_AUX_ERR_NACK;
> + } else if (!aux->native && (isr & DP_INTR_I2C_DEFER)) {
> + if (isr & DP_INTR_AUX_XFER_DONE)
> + aux->aux_error_num = DP_AUX_ERR_NACK;
> + else
> + aux->aux_error_num = DP_AUX_ERR_DEFER;
> + } else {
> + DRM_WARN("Unexpected interrupt: %#010x\n", isr);
> + return;
> + }
>
> complete(&aux->comp);
> }
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
> index 676279d0ca8d..421391755427 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
> @@ -27,7 +27,7 @@
> #define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4)
>
> #define DP_INTERRUPT_STATUS1 \
> - (DP_INTR_AUX_I2C_DONE| \
> + (DP_INTR_AUX_XFER_DONE| \
> DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \
> DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \
> DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
> index 1f717f45c115..f36b7b372a06 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.h
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
> @@ -13,7 +13,7 @@
>
> /* interrupts */
> #define DP_INTR_HPD BIT(0)
> -#define DP_INTR_AUX_I2C_DONE BIT(3)
> +#define DP_INTR_AUX_XFER_DONE BIT(3)
> #define DP_INTR_WRONG_ADDR BIT(6)
> #define DP_INTR_TIMEOUT BIT(9)
> #define DP_INTR_NACK_DEFER BIT(12)
More information about the dri-devel
mailing list