From patchwork Fri Aug 23 03:37:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Williams X-Patchwork-Id: 1151914 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=marvell.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=marvell.com header.i=@marvell.com header.b="dt+TOW6A"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46F6Z16Fv9z9s7T for ; Fri, 23 Aug 2019 13:38:33 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 87B75C2210B; Fri, 23 Aug 2019 03:37:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 12245C220DD; Fri, 23 Aug 2019 03:37:40 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 1A682C22047; Fri, 23 Aug 2019 03:37:37 +0000 (UTC) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by lists.denx.de (Postfix) with ESMTPS id 3D636C22047 for ; Fri, 23 Aug 2019 03:37:37 +0000 (UTC) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id x7N3ZWDg001794; Thu, 22 Aug 2019 20:37:33 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=pfpt0818; bh=ZM2YWFhtF3CnNwg77/V5fXybXIniAym1l/q5gaICt/Q=; b=dt+TOW6AcU9D4Ztv9wxgaWsvAXSM10Ce33gTCwK+s23O5eHqeM4BTGJnbUc3xFOk4pCX IonlYbiNcOe98Y1Y/MKCUL9lJaC1xYz4LyyJQVwzsRYgnXwdRro+/Apu7I6VW+q18NSS b/E0Q6x6mVeXhYnuwTRlPo24bYlfqWDL3HsXuDSxYTIqNEk3ltggfOdQQoLyJcMQVyH3 mFIB+VK6BcnBT2uNk6acnPv6Gac9qU9PSwfONjXvKIELo5Ag6sWQilXZqcJosyEsWO5z j7IYxYAnHjVzfjO9vxFbSWw93zMmH6xM/zZ7JOZNhDJYS21NRu1xLUuY9/ZrNTYsaqU5 gw== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0a-0016f401.pphosted.com with ESMTP id 2uhad3y131-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Thu, 22 Aug 2019 20:37:32 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 22 Aug 2019 20:37:32 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Thu, 22 Aug 2019 20:37:31 -0700 Received: from marvell.com (unknown [10.85.93.181]) by maili.marvell.com (Postfix) with ESMTP id C34813F703F; Thu, 22 Aug 2019 20:37:31 -0700 (PDT) From: Aaron Williams To: Date: Thu, 22 Aug 2019 20:37:26 -0700 Message-ID: <20190823033728.24591-1-awilliams@marvell.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: References: MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:5.22.84,1.0.8 definitions=2019-08-22_15:2019-08-21,2019-08-22 signatures=0 Subject: [U-Boot] [PATCH v4 1/1] nvme: Fix PRP Offset Invalid X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" When large writes take place I saw a Samsung EVO 970+ return a status value of 0x13, PRP Offset Invalid. I tracked this down to the improper handling of PRP entries. The blocks the PRP entries are placed in cannot cross a page boundary and thus should be allocated on page boundaries. This is how the Linux kernel driver works. With this patch, the PRP pool is allocated on a page boundary and other than the very first allocation, the pool size is a multiple of the page size. Each page can hold (4096 / 8) - 1 entries since the last entry must point to the next page in the pool. Signed-off-by: Aaron Williams Reviewed-by: Bin Meng --- drivers/nvme/nvme.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) -- 2.16.4 diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index d4965e2ef6..47f101e280 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -73,6 +73,9 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, u64 *prp_pool; int length = total_len; int i, nprps; + u32 prps_per_page = (page_size >> 3) - 1; + u32 num_pages; + length -= (page_size - offset); if (length <= 0) { @@ -89,15 +92,20 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, } nprps = DIV_ROUND_UP(length, page_size); + num_pages = DIV_ROUND_UP(nprps, prps_per_page); if (nprps > dev->prp_entry_num) { free(dev->prp_pool); - dev->prp_pool = malloc(nprps << 3); + /* + * Always increase in increments of pages. It doesn't waste + * much memory and reduces the number of allocations. + */ + dev->prp_pool = memalign(page_size, num_pages * page_size); if (!dev->prp_pool) { printf("Error: malloc prp_pool fail\n"); return -ENOMEM; } - dev->prp_entry_num = nprps; + dev->prp_entry_num = prps_per_page * num_pages; } prp_pool = dev->prp_pool; @@ -788,14 +796,6 @@ static int nvme_probe(struct udevice *udev) } memset(ndev->queues, 0, NVME_Q_NUM * sizeof(struct nvme_queue *)); - ndev->prp_pool = malloc(MAX_PRP_POOL); - if (!ndev->prp_pool) { - ret = -ENOMEM; - printf("Error: %s: Out of memory!\n", udev->name); - goto free_nvme; - } - ndev->prp_entry_num = MAX_PRP_POOL >> 3; - ndev->cap = nvme_readq(&ndev->bar->cap); ndev->q_depth = min_t(int, NVME_CAP_MQES(ndev->cap) + 1, NVME_Q_DEPTH); ndev->db_stride = 1 << NVME_CAP_STRIDE(ndev->cap); @@ -805,6 +805,15 @@ static int nvme_probe(struct udevice *udev) if (ret) goto free_queue; + /* Allocate after the page size is known */ + ndev->prp_pool = memalign(ndev->page_size, MAX_PRP_POOL); + if (!ndev->prp_pool) { + ret = -ENOMEM; + printf("Error: %s: Out of memory!\n", udev->name); + goto free_nvme; + } + ndev->prp_entry_num = MAX_PRP_POOL >> 3; + ret = nvme_setup_io_queues(ndev); if (ret) goto free_queue;