aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 1e364d3ad9c5..f0523916232d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -744,32 +744,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
744} 744}
745 745
746static int its_wait_for_range_completion(struct its_node *its, 746static int its_wait_for_range_completion(struct its_node *its,
747 struct its_cmd_block *from, 747 u64 prev_idx,
748 struct its_cmd_block *to) 748 struct its_cmd_block *to)
749{ 749{
750 u64 rd_idx, from_idx, to_idx; 750 u64 rd_idx, to_idx, linear_idx;
751 u32 count = 1000000; /* 1s! */ 751 u32 count = 1000000; /* 1s! */
752 752
753 from_idx = its_cmd_ptr_to_offset(its, from); 753 /* Linearize to_idx if the command set has wrapped around */
754 to_idx = its_cmd_ptr_to_offset(its, to); 754 to_idx = its_cmd_ptr_to_offset(its, to);
755 if (to_idx < prev_idx)
756 to_idx += ITS_CMD_QUEUE_SZ;
757
758 linear_idx = prev_idx;
755 759
756 while (1) { 760 while (1) {
761 s64 delta;
762
757 rd_idx = readl_relaxed(its->base + GITS_CREADR); 763 rd_idx = readl_relaxed(its->base + GITS_CREADR);
758 764
759 /* Direct case */ 765 /*
760 if (from_idx < to_idx && rd_idx >= to_idx) 766 * Compute the read pointer progress, taking the
761 break; 767 * potential wrap-around into account.
768 */
769 delta = rd_idx - prev_idx;
770 if (rd_idx < prev_idx)
771 delta += ITS_CMD_QUEUE_SZ;
762 772
763 /* Wrapped case */ 773 linear_idx += delta;
764 if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx) 774 if (linear_idx >= to_idx)
765 break; 775 break;
766 776
767 count--; 777 count--;
768 if (!count) { 778 if (!count) {
769 pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n", 779 pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
770 from_idx, to_idx, rd_idx); 780 to_idx, linear_idx);
771 return -1; 781 return -1;
772 } 782 }
783 prev_idx = rd_idx;
773 cpu_relax(); 784 cpu_relax();
774 udelay(1); 785 udelay(1);
775 } 786 }
@@ -786,6 +797,7 @@ void name(struct its_node *its, \
786 struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ 797 struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
787 synctype *sync_obj; \ 798 synctype *sync_obj; \
788 unsigned long flags; \ 799 unsigned long flags; \
800 u64 rd_idx; \
789 \ 801 \
790 raw_spin_lock_irqsave(&its->lock, flags); \ 802 raw_spin_lock_irqsave(&its->lock, flags); \
791 \ 803 \
@@ -807,10 +819,11 @@ void name(struct its_node *its, \
807 } \ 819 } \
808 \ 820 \
809post: \ 821post: \
822 rd_idx = readl_relaxed(its->base + GITS_CREADR); \
810 next_cmd = its_post_commands(its); \ 823 next_cmd = its_post_commands(its); \
811 raw_spin_unlock_irqrestore(&its->lock, flags); \ 824 raw_spin_unlock_irqrestore(&its->lock, flags); \
812 \ 825 \
813 if (its_wait_for_range_completion(its, cmd, next_cmd)) \ 826 if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
814 pr_err_ratelimited("ITS cmd %ps failed\n", builder); \ 827 pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
815} 828}
816 829