| From bf51b2f4266049a7ac6cf8caf380d6fef669d636 Mon Sep 17 00:00:00 2001 |
| From: Steve Longerbeam <slongerbeam@gmail.com> |
| Date: Thu, 25 Jun 2020 11:13:37 -0700 |
| Subject: [PATCH] gpu: ipu-v3: image-convert: Wait for all EOFs before |
| completing a tile |
| |
| commit dd81d821d0b3f77d949d0cac5c05c1f05b921d46 upstream. |
| |
| Use a bit-mask of EOF irqs to determine when all required idmac |
| channel EOFs have been received for a tile conversion, and only do |
| tile completion processing after all EOFs have been received. Otherwise |
| it was found that a conversion would stall after the completion of a |
| tile and the start of the next tile, because the input/read idmac |
| channel had not completed and entered idle state, thus locking up the |
| channel when attempting to re-start it for the next tile. |
| |
| Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile") |
| Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com> |
| Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> |
| |
| diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c |
| index 42d9cd856ed3..9d3b965b128e 100644 |
| --- a/drivers/gpu/ipu-v3/ipu-image-convert.c |
| +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c |
| @@ -137,6 +137,17 @@ struct ipu_image_convert_ctx; |
| struct ipu_image_convert_chan; |
| struct ipu_image_convert_priv; |
| |
| +enum eof_irq_mask { |
| + EOF_IRQ_IN = BIT(0), |
| + EOF_IRQ_ROT_IN = BIT(1), |
| + EOF_IRQ_OUT = BIT(2), |
| + EOF_IRQ_ROT_OUT = BIT(3), |
| +}; |
| + |
| +#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT) |
| +#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT | \ |
| + EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT) |
| + |
| struct ipu_image_convert_ctx { |
| struct ipu_image_convert_chan *chan; |
| |
| @@ -172,6 +183,9 @@ struct ipu_image_convert_ctx { |
| /* where to place converted tile in dest image */ |
| unsigned int out_tile_map[MAX_TILES]; |
| |
| + /* mask of completed EOF irqs at every tile conversion */ |
| + enum eof_irq_mask eof_mask; |
| + |
| struct list_head list; |
| }; |
| |
| @@ -188,6 +202,8 @@ struct ipu_image_convert_chan { |
| struct ipuv3_channel *rotation_out_chan; |
| |
| /* the IPU end-of-frame irqs */ |
| + int in_eof_irq; |
| + int rot_in_eof_irq; |
| int out_eof_irq; |
| int rot_out_eof_irq; |
| |
| @@ -1361,6 +1377,9 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) |
| init_idmac_channel(ctx, chan->in_chan, s_image, |
| IPU_ROTATE_NONE, false, tile); |
| |
| + /* clear EOF irq mask */ |
| + ctx->eof_mask = 0; |
| + |
| if (ipu_rot_mode_is_irt(ctx->rot_mode)) { |
| /* init the IC PP-->MEM IDMAC channel */ |
| init_idmac_channel(ctx, chan->out_chan, d_image, |
| @@ -1559,7 +1578,7 @@ static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx) |
| } |
| |
| /* hold irqlock when calling */ |
| -static irqreturn_t do_irq(struct ipu_image_convert_run *run) |
| +static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run) |
| { |
| struct ipu_image_convert_ctx *ctx = run->ctx; |
| struct ipu_image_convert_chan *chan = ctx->chan; |
| @@ -1644,6 +1663,7 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run) |
| ctx->cur_buf_num ^= 1; |
| } |
| |
| + ctx->eof_mask = 0; /* clear EOF irq mask for next tile */ |
| ctx->next_tile++; |
| return IRQ_HANDLED; |
| done: |
| @@ -1659,8 +1679,9 @@ static irqreturn_t eof_irq(int irq, void *data) |
| struct ipu_image_convert_priv *priv = chan->priv; |
| struct ipu_image_convert_ctx *ctx; |
| struct ipu_image_convert_run *run; |
| + irqreturn_t ret = IRQ_HANDLED; |
| + bool tile_complete = false; |
| unsigned long flags; |
| - irqreturn_t ret; |
| |
| spin_lock_irqsave(&chan->irqlock, flags); |
| |
| @@ -1673,27 +1694,33 @@ static irqreturn_t eof_irq(int irq, void *data) |
| |
| ctx = run->ctx; |
| |
| - if (irq == chan->out_eof_irq) { |
| - if (ipu_rot_mode_is_irt(ctx->rot_mode)) { |
| - /* this is a rotation op, just ignore */ |
| - ret = IRQ_HANDLED; |
| - goto out; |
| - } |
| - } else if (irq == chan->rot_out_eof_irq) { |
| + if (irq == chan->in_eof_irq) { |
| + ctx->eof_mask |= EOF_IRQ_IN; |
| + } else if (irq == chan->out_eof_irq) { |
| + ctx->eof_mask |= EOF_IRQ_OUT; |
| + } else if (irq == chan->rot_in_eof_irq || |
| + irq == chan->rot_out_eof_irq) { |
| if (!ipu_rot_mode_is_irt(ctx->rot_mode)) { |
| /* this was NOT a rotation op, shouldn't happen */ |
| dev_err(priv->ipu->dev, |
| "Unexpected rotation interrupt\n"); |
| - ret = IRQ_HANDLED; |
| goto out; |
| } |
| + ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ? |
| + EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT; |
| } else { |
| dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq); |
| ret = IRQ_NONE; |
| goto out; |
| } |
| |
| - ret = do_irq(run); |
| + if (ipu_rot_mode_is_irt(ctx->rot_mode)) |
| + tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE); |
| + else |
| + tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE); |
| + |
| + if (tile_complete) |
| + ret = do_tile_complete(run); |
| out: |
| spin_unlock_irqrestore(&chan->irqlock, flags); |
| return ret; |
| @@ -1727,6 +1754,10 @@ static void force_abort(struct ipu_image_convert_ctx *ctx) |
| |
| static void release_ipu_resources(struct ipu_image_convert_chan *chan) |
| { |
| + if (chan->in_eof_irq >= 0) |
| + free_irq(chan->in_eof_irq, chan); |
| + if (chan->rot_in_eof_irq >= 0) |
| + free_irq(chan->rot_in_eof_irq, chan); |
| if (chan->out_eof_irq >= 0) |
| free_irq(chan->out_eof_irq, chan); |
| if (chan->rot_out_eof_irq >= 0) |
| @@ -1745,7 +1776,27 @@ static void release_ipu_resources(struct ipu_image_convert_chan *chan) |
| |
| chan->in_chan = chan->out_chan = chan->rotation_in_chan = |
| chan->rotation_out_chan = NULL; |
| - chan->out_eof_irq = chan->rot_out_eof_irq = -1; |
| + chan->in_eof_irq = -1; |
| + chan->rot_in_eof_irq = -1; |
| + chan->out_eof_irq = -1; |
| + chan->rot_out_eof_irq = -1; |
| +} |
| + |
| +static int get_eof_irq(struct ipu_image_convert_chan *chan, |
| + struct ipuv3_channel *channel) |
| +{ |
| + struct ipu_image_convert_priv *priv = chan->priv; |
| + int ret, irq; |
| + |
| + irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF); |
| + |
| + ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan); |
| + if (ret < 0) { |
| + dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq); |
| + return ret; |
| + } |
| + |
| + return irq; |
| } |
| |
| static int get_ipu_resources(struct ipu_image_convert_chan *chan) |
| @@ -1781,31 +1832,33 @@ static int get_ipu_resources(struct ipu_image_convert_chan *chan) |
| } |
| |
| /* acquire the EOF interrupts */ |
| - chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu, |
| - chan->out_chan, |
| - IPU_IRQ_EOF); |
| + ret = get_eof_irq(chan, chan->in_chan); |
| + if (ret < 0) { |
| + chan->in_eof_irq = -1; |
| + goto err; |
| + } |
| + chan->in_eof_irq = ret; |
| |
| - ret = request_threaded_irq(chan->out_eof_irq, eof_irq, do_bh, |
| - 0, "ipu-ic", chan); |
| + ret = get_eof_irq(chan, chan->rotation_in_chan); |
| if (ret < 0) { |
| - dev_err(priv->ipu->dev, "could not acquire irq %d\n", |
| - chan->out_eof_irq); |
| - chan->out_eof_irq = -1; |
| + chan->rot_in_eof_irq = -1; |
| goto err; |
| } |
| + chan->rot_in_eof_irq = ret; |
| |
| - chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu, |
| - chan->rotation_out_chan, |
| - IPU_IRQ_EOF); |
| + ret = get_eof_irq(chan, chan->out_chan); |
| + if (ret < 0) { |
| + chan->out_eof_irq = -1; |
| + goto err; |
| + } |
| + chan->out_eof_irq = ret; |
| |
| - ret = request_threaded_irq(chan->rot_out_eof_irq, eof_irq, do_bh, |
| - 0, "ipu-ic", chan); |
| + ret = get_eof_irq(chan, chan->rotation_out_chan); |
| if (ret < 0) { |
| - dev_err(priv->ipu->dev, "could not acquire irq %d\n", |
| - chan->rot_out_eof_irq); |
| chan->rot_out_eof_irq = -1; |
| goto err; |
| } |
| + chan->rot_out_eof_irq = ret; |
| |
| return 0; |
| err: |
| @@ -2371,6 +2424,8 @@ int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev) |
| chan->ic_task = i; |
| chan->priv = priv; |
| chan->dma_ch = &image_convert_dma_chan[i]; |
| + chan->in_eof_irq = -1; |
| + chan->rot_in_eof_irq = -1; |
| chan->out_eof_irq = -1; |
| chan->rot_out_eof_irq = -1; |
| |
| -- |
| 2.27.0 |
| |