From patchwork Tue Mar 6 07:06:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yang Yingliang X-Patchwork-Id: 10260867 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0B2BC602C8 for ; Tue, 6 Mar 2018 07:08:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EB80A28E5B for ; Tue, 6 Mar 2018 07:08:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E02E628E6F; Tue, 6 Mar 2018 07:08:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4F3C928E5B for ; Tue, 6 Mar 2018 07:08:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender:Content-Type: Content-Transfer-Encoding:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:Date:Message-ID:From: References:To:Subject:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=ghuQri+lvPPSBuvaYo+0V0tc3yPzf4MkxsULQiz2YNg=; b=OuRKmdvb9/XNnbqLevh2n6AgZ OperlejCIvemSLLVHHDgJc8qgi84QegHRwzw9nMud+S7epNPzWRyG4nkbakmIUZhuYp3allVnkITe h9oa3LbadT0qfYxwmJcL9gwUR6lR3TdjoIHb6Z8pbgJSVty1KPKNRhEh4Ky2UMcz6qCh8WoQ4SAfF 0hc7ORzpwEe2fOTz3TN7tzNpQFUllvSJpeKMPLz59qYQpwRQZK25SCp1Yf9Rh2C09/IGPJfdWjLyl XGew4d2xx73jQwXa4j2RKkjjbWmh28xakGZpRCoGsmb/ep9Ht7CUtPK4HUwTMcpsfjD173sDuKpBv b6rLQ9lpw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1et6iL-0004K7-7W; Tue, 06 Mar 2018 07:08:45 +0000 Received: from szxga05-in.huawei.com ([45.249.212.191] helo=huawei.com) by bombadil.infradead.org with esmtps (Exim 4.89 #1 (Red Hat Linux)) id 1et6iH-0004HO-DG for linux-arm-kernel@lists.infradead.org; Tue, 06 Mar 2018 07:08:43 +0000 Received: from DGGEMS401-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id ACBCCD31F1FC3; Tue, 6 Mar 2018 15:08:04 +0800 (CST) Received: from [127.0.0.1] (10.177.19.219) by DGGEMS401-HUB.china.huawei.com (10.3.19.201) with Microsoft SMTP Server id 14.3.361.1; Tue, 6 Mar 2018 15:07:57 +0800 Subject: [RFC PATCH] irqchip/gic-v3-its: handle wrapped case in its_wait_for_range_completion() To: Marc Zyngier References: <1518320521-12536-1-git-send-email-yangyingliang@huawei.com> <866073z7pr.wl-marc.zyngier@arm.com> From: Yang Yingliang Message-ID: <5A9E3E13.6060207@huawei.com> Date: Tue, 6 Mar 2018 15:06:59 +0800 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.5.1 MIME-Version: 1.0 In-Reply-To: <866073z7pr.wl-marc.zyngier@arm.com> X-Originating-IP: [10.177.19.219] X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180305_230841_632434_DC81EF80 X-CRM114-Status: GOOD ( 14.88 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: LKML , linux-arm-kernel@lists.infradead.org, Yangyingliang Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Yang Yingliang While cpus posting a bunch of ITS commands, the cmd_queue and rd_idx will be wrapped easily. And current way of handling wrapped case is not quite right. Such as, in direct case, rd_idx will wrap if other cpus post commands that make rd_idx increase. When rd_idx wrapped, the driver prints timeout messages but in fact the command is finished. This patch adds two variables to count wrapped times of ITS commands and read index. With these two variables, the driver can handle wrapped case correctly. Signed-off-by: Yang Yingliang --- drivers/irqchip/irq-gic-v3-its.c | 72 +++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 12 deletions(-) cmd->raw_cmd[0] = 0; @@ -713,29 +730,57 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) static int its_wait_for_range_completion(struct its_node *its, struct its_cmd_block *from, - struct its_cmd_block *to) + struct its_cmd_block *to, + u64 last_cmd_wrapped_cnt) { - u64 rd_idx, from_idx, to_idx; + unsigned long flags; + u64 rd_idx, from_idx, to_idx, rd_wrapped_cnt; u32 count = 1000000; /* 1s! */ from_idx = its_cmd_ptr_to_offset(its, from); to_idx = its_cmd_ptr_to_offset(its, to); while (1) { + raw_spin_lock_irqsave(&its->lock, flags); rd_idx = readl_relaxed(its->base + GITS_CREADR); + if (rd_idx < its->last_rd) + its->rd_wrapped_cnt++; + its->last_rd = rd_idx; + rd_wrapped_cnt = its->rd_wrapped_cnt; + raw_spin_unlock_irqrestore(&its->lock, flags); - /* Direct case */ - if (from_idx < to_idx && rd_idx >= to_idx) - break; - - /* Wrapped case */ - if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx) + /* + * If rd_wrapped_cnt > last_cmd_wrapped_cnt: + * there are a lot of ITS commands posted by + * other cpus and ITS is fast. + * + * If rd_wrapped_cnt < last_cmd_wrapped_cnt: + * ITS is slow, there are some ITS commands + * not finished. + * + * If rd_wrapped_cnt == last_cmd_wrapped_cnt: + * it's common case. + */ + if (rd_wrapped_cnt > last_cmd_wrapped_cnt) { + /* + * There is a lot of ITS commands posted by other cpus, + * it make rd_idx move foward fast and wrap. + */ break; + } else if (rd_wrapped_cnt == last_cmd_wrapped_cnt) { + /* Direct case */ + if (from_idx < to_idx && rd_idx >= to_idx) + break; + + /* Wrapped case */ + if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx) + break; + } count--; if (!count) { - pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n", - from_idx, to_idx, rd_idx); + pr_err_ratelimited("ITS queue timeout (%llu %llu %llu) %llu %llu\n", + from_idx, to_idx, rd_idx, rd_wrapped_cnt, last_cmd_wrapped_cnt); return -1; } cpu_relax(); @@ -754,6 +799,7 @@ void name(struct its_node *its, \ struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ synctype *sync_obj; \ unsigned long flags; \ + u64 cmd_wrapped_cnt; \ \ raw_spin_lock_irqsave(&its->lock, flags); \ \ @@ -776,9 +822,11 @@ void name(struct its_node *its, \ \ post: \ next_cmd = its_post_commands(its); \ + cmd_wrapped_cnt = its->cmd_wrapped_cnt; \ raw_spin_unlock_irqrestore(&its->lock, flags); \ \ - if (its_wait_for_range_completion(its, cmd, next_cmd)) \ + if (its_wait_for_range_completion(its, cmd, next_cmd, \ + cmd_wrapped_cnt)) \ pr_err_ratelimited("ITS cmd %ps failed\n", builder); \ } diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1d3056f..a03e18e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -111,6 +111,9 @@ struct its_node { u32 pre_its_base; /* for Socionext Synquacer */ bool is_v4; int vlpi_redist_offset; + int last_rd; + u64 cmd_wrapped_cnt; + u64 rd_wrapped_cnt; }; #define ITS_ITT_ALIGN SZ_256 @@ -662,6 +665,7 @@ static int its_queue_full(struct its_node *its) static struct its_cmd_block *its_allocate_entry(struct its_node *its) { + u32 rd; struct its_cmd_block *cmd; u32 count = 1000000; /* 1s! */ @@ -675,11 +679,24 @@ static struct its_cmd_block *its_allocate_entry(struct its_node *its) udelay(1); } + /* + * Here is protected by its->lock and driver cannot allocate + * ITS commands, if ITS command queue is full, so the read + * won't wrap twice between this rd_idx and last rd_idx. + * Count rd wrapped times here is safe. + */ + rd = readl_relaxed(its->base + GITS_CREADR); + if (rd < its->last_rd) + its->rd_wrapped_cnt++; + its->last_rd = rd; + cmd = its->cmd_write++; /* Handle queue wrapping */ - if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES)) + if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES)) { its->cmd_write = its->cmd_base; + its->cmd_wrapped_cnt++; + } /* Clear command */