diff options
| -rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 35 |
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 | ||
| 746 | static int its_wait_for_range_completion(struct its_node *its, | 746 | static 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 | \ |
| 809 | post: \ | 821 | post: \ |
| 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 | ||
