From patchwork Thu Sep 2 14:00:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Price X-Patchwork-Id: 12471769 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E6AFEC432BE for ; Thu, 2 Sep 2021 14:01:09 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9F3CB610CC for ; Thu, 2 Sep 2021 14:01:09 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 9F3CB610CC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B5A036E4D4; Thu, 2 Sep 2021 14:01:08 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by gabe.freedesktop.org (Postfix) with ESMTP id 4485C6E528 for ; Thu, 2 Sep 2021 14:01:07 +0000 (UTC) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4B5D61FB; Thu, 2 Sep 2021 07:01:06 -0700 (PDT) Received: from e122027.lan (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EB69F3F5A1; Thu, 2 Sep 2021 07:01:04 -0700 (PDT) From: Steven Price To: Rob Herring , Tomeu Vizoso , Alyssa Rosenzweig , Boris Brezillon Cc: Steven Price , Daniel Vetter , David Airlie , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org Subject: [PATCH] drm/panfrost: Calculate lock region size correctly Date: Thu, 2 Sep 2021 15:00:38 +0100 Message-Id: <20210902140038.221437-1-steven.price@arm.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" It turns out that when locking a region, the region must be a naturally aligned power of 2. The upshot of this is that if the desired region crosses a 'large boundary' the region size must be increased significantly to ensure that the locked region completely covers the desired region. Previous calculations (including in kbase for the proprietary driver) failed to take this into account. Since it's known that the lock region must be naturally aligned we can compute the required size by looking at the highest bit position which changes between the start/end of the lock region (subtracting 1 from the end because the end address is exclusive). The start address is then aligned based on the size (this is technically unnecessary as the hardware will ignore these bits, but the spec advises to do this "to avoid confusion"). Signed-off-by: Steven Price Reviewed-by: Boris Brezillon --- See previous discussion[1] for more details. This bug also existed in the 'kbase' driver, so it's unlikely to actually hit very often. This patch is based on drm-misc-next-fixes as it builds on top of Alyssa's changes to lock_region. [1] https://lore.kernel.org/dri-devel/6fe675c4-d22b-22da-ba3c-f6d33419b9ed@arm.com/ drivers/gpu/drm/panfrost/panfrost_mmu.c | 33 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index dfe5f1d29763..afec15bb3db5 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -58,17 +58,36 @@ static int write_cmd(struct panfrost_device *pfdev, u32 as_nr, u32 cmd) } static void lock_region(struct panfrost_device *pfdev, u32 as_nr, - u64 iova, u64 size) + u64 region_start, u64 size) { u8 region_width; - u64 region = iova & PAGE_MASK; + u64 region; + u64 region_size; + u64 region_end = region_start + size; - /* The size is encoded as ceil(log2) minus(1), which may be calculated - * with fls. The size must be clamped to hardware bounds. + if (!size) + return; + + /* + * The locked region is a naturally aligned power of 2 block encoded as + * log2 minus(1). + * Calculate the desired start/end and look for the highest bit which + * differs. The smallest naturally aligned block must include this bit + * change the desired region starts with this bit (and subsequent bits) + * zeroed and ends with the bit (and subsequent bits) set to one. + * */ - size = max_t(u64, size, AS_LOCK_REGION_MIN_SIZE); - region_width = fls64(size - 1) - 1; - region |= region_width; + region_size = region_start ^ (region_end - 1); + region_width = max(fls64(region_size), + const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1; + + /* + * Mask off the low bits of region_start (which would be ignored by + * the hardware anyway) + */ + region_start &= GENMASK_ULL(63, region_width); + + region = region_width | region_start; /* Lock the region that needs to be updated */ mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), region & 0xFFFFFFFFUL);