Message ID | 20221205105931.410686-4-vadym.kochan@plvision.eu |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp2181754wrr; Mon, 5 Dec 2022 03:04:18 -0800 (PST) X-Google-Smtp-Source: AA0mqf6d2j1neC5MmgQcfLt/FlFK2UHRpPEB3rCMSx8FmfbkjKCLEiF0qmWnT2FreQNZjipnepli X-Received: by 2002:a17:906:94e:b0:7ba:4617:3f17 with SMTP id j14-20020a170906094e00b007ba46173f17mr47007202ejd.226.1670238258542; Mon, 05 Dec 2022 03:04:18 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1670238258; cv=pass; d=google.com; s=arc-20160816; b=YvkrF/tGTUxUO9TzUkBZDzYQbw/uruvdPDqaEHkGSbsjjbFW9iPYDDNjU1hbnIBRFI pfcVnuc8ZBiibGnr8pZ5ySHk9+M41qVQUx34mi5G2+D3a1FMP9UTrS0dEOE9yJG121lD 3RdKs0G2LHxZNxetqRc0/CHeeRE2cwiOPoRSK94qInn2RCRLvsLUgJg17R8yh5gqYx4f H3kWO+VH46zUwiYym+pAPdUWx28fWDCDdyeRD5E4d0l82+P4PGRV51kfozAT/VEo59ba dV3K3Nb0lCmw3GNRrFTZMoQ0uFBV/ictSTrMe4Dv9uKz29NATtz0xAmsHGposF/P0JfJ dONg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:content-transfer-encoding :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=FuldcKvKeWXVmKDJ7yaKSDt9K0l06pHPOxoH4W4h1gY=; b=Y8ANy/LnxRfiAsU6qP2kt/LZJk/NQ6Q0LM8TFfhkiAy51rVJIWXlNjq0PrhuAXNLhn WAgtX0YZuG9QQA3c7H6MEpHrG2s43G5QC6Rw4ShLzwq2+hx0vU2Tks/EajmsJlEZntBr j3O/JQ7FXt7zOrvy/BeLqNau2FwiZNABensJpr0+GrYA+eGVu/X+cOG+90vVqvzSYexP 2Q1ABt0ftQ2x7ZgzRk++jk4Z/jwxT/8J6x/rEC3zOtD2V0QqyDV/z6UE3lUQys8LYG2O YlHdbEIxc4kMMcS/8eQgTkxGZG/SNOr1VfXdxCjLPV8vXn32Et8LOfxGgM1GknlaDzru jFhQ== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@plvision.eu header.s=selector2 header.b=dK2HoMVg; arc=pass (i=1 spf=pass spfdomain=plvision.eu dkim=pass dkdomain=plvision.eu dmarc=pass fromdomain=plvision.eu); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=plvision.eu Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id wy1-20020a170906fe0100b007bc30c06aa2si9717838ejb.902.2022.12.05.03.03.53; Mon, 05 Dec 2022 03:04:18 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@plvision.eu header.s=selector2 header.b=dK2HoMVg; arc=pass (i=1 spf=pass spfdomain=plvision.eu dkim=pass dkdomain=plvision.eu dmarc=pass fromdomain=plvision.eu); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=plvision.eu Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230160AbiLELA3 (ORCPT <rfc822;jaysivo@gmail.com> + 99 others); Mon, 5 Dec 2022 06:00:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230508AbiLELAB (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 5 Dec 2022 06:00:01 -0500 Received: from EUR02-VI1-obe.outbound.protection.outlook.com (mail-vi1eur02on2118.outbound.protection.outlook.com [40.107.241.118]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B255019292; Mon, 5 Dec 2022 03:00:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Ic9l6lw6d7AQwrJoo4eELrx6h6ZuqczNDl79CU0hG2LWjsTZANClr9Ttl3/95rvG3xL8/pqevATnKwP7sek9fJyNKHTdlhAleWhHwVqJpUPtDnjIUsF4fD4OhELFCXBSwp/dbvMuNygG6KPbsOHMMBZbcE2WuOhsSe5Ub+KPBhF3DcXmkAh8kdLWswfDRuwDgklkfj6GGkCCVdxtLFU5dvgmCrFqATVYoH5netYuSKmK2oju9etr+2lpZ4YqDnKYM/Oz9dIgPm1yRe5ClfyCsQSStyy2Umf//YuZE0kslhytEHsb3N31aUmXvKKZyExRjL9SZk9pawN+dpCx86rQZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FuldcKvKeWXVmKDJ7yaKSDt9K0l06pHPOxoH4W4h1gY=; b=bvhoc3qJiEMTGROY8JWZDMtLA6HoQhGSp5sS5y/N1sAb3K+zja3g2e5mqAlQLGztXRrTZqfUtZ39jUywP0TG7SkvuSpBkmOmefilIoTG+h1vnyDxogMrTto/283jzAD7bfFhuo8BkXT3lZg+Zi4DVoYC/Ymz+04zeUOa0n6icOC5hpHN57SjTycOU+spX0gXy/sCdAYrkyDUYxmbX1KdNHb2tGDTQo4zikcGMQJrkul3I9tKy7N/xsXO2NiAJGFlSyshqioUQKPROolS6o44vpoUCRZu/zBXuvtnfRjNbb5UfM6DR4Iz9d6oBYLdr+g6GyWRjgX6+OOwb9n7HoEUyg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=plvision.eu; dmarc=pass action=none header.from=plvision.eu; dkim=pass header.d=plvision.eu; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=plvision.eu; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FuldcKvKeWXVmKDJ7yaKSDt9K0l06pHPOxoH4W4h1gY=; b=dK2HoMVgHF4TMoT+Ar6hoxmcRHCYM4KeregMPWw8BCszlw5zD34heAkXB6IscnZcJnx5QWi0iTEkJkxrKquTeJ8RzFPoZOv32Ohwv8pDG+0M2pi1r5cR/b1OczhqJLhqh9kVpXzEaqnAcMf+lL6zYRWTKjW8CYrH+YWoOpIT5dw= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=plvision.eu; Received: from VI1P190MB0317.EURP190.PROD.OUTLOOK.COM (2603:10a6:802:38::26) by AM8P190MB0980.EURP190.PROD.OUTLOOK.COM (2603:10a6:20b:1da::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5880.14; Mon, 5 Dec 2022 10:59:51 +0000 Received: from VI1P190MB0317.EURP190.PROD.OUTLOOK.COM ([fe80::5912:e2b4:985e:265a]) by VI1P190MB0317.EURP190.PROD.OUTLOOK.COM ([fe80::5912:e2b4:985e:265a%3]) with mapi id 15.20.5880.013; Mon, 5 Dec 2022 10:59:51 +0000 From: Vadym Kochan <vadym.kochan@plvision.eu> To: Hu Ziji <huziji@marvell.com>, Ulf Hansson <ulf.hansson@linaro.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Adrian Hunter <adrian.hunter@intel.com>, linux-mmc@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Elad Nachman <enachman@marvell.com>, Chris Packham <chris.packham@alliedtelesis.co.nz>, Vadym Kochan <vadym.kochan@plvision.eu> Subject: [PATCH v3 3/3] mmc: xenon: Fix 2G limitation on AC5 SoC Date: Mon, 5 Dec 2022 12:59:30 +0200 Message-Id: <20221205105931.410686-4-vadym.kochan@plvision.eu> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20221205105931.410686-1-vadym.kochan@plvision.eu> References: <20221205105931.410686-1-vadym.kochan@plvision.eu> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: FRYP281CA0018.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10::28) To VI1P190MB0317.EURP190.PROD.OUTLOOK.COM (2603:10a6:802:38::26) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1P190MB0317:EE_|AM8P190MB0980:EE_ X-MS-Office365-Filtering-Correlation-Id: ba06d64a-842c-4ae7-6165-08dad6afd538 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: yP99TKulsQ/XPm1R3zFFu8E4YHKtOx36NsL11kHm8R0yAeRRgxsfBhzHcfVeWkABqUk+PaHfLDirm5M180KAQ5qd5w14SwW0g//5n2FMqSTuKtK9fifxuwE1u0lSC6wD0R/Ob2mPZB5grvqKhj4W/PjXo+NwzMvKRXYY3Rh3XRJs8G9Xr0Kgc2YXr5LFdaXRyPA4yeWtEWnwyh+ZygEED2VG2E0Hwa3MQ6/E+rHRtjva0JOY6ng+kKXbjuUR9GK/LE6o/Tb0D3eMs3hc92vMmSoRrkEg7aaqzSYfz5+SxtZK4u06BKs6swY1S46lTGDE8kuCNsu7+rWuwem/+pzMLXiy8GDAav5XWqXsVwOOElFBe3NQjJurnplo3FXWAWIanPztnjZ/eQdftpzmXS5zxLeATpftB7RJPpPS5Y21Z5R70253Nxn0IsIsA8Boi4weYJebAGn15p6OViMUKdMUDhdD/bDFDEYRs8antR8GAn8wA8TKLVt5DzKwXctLauU22K+P0EsmlfxVhVdJGjaCorn8UNsWqCeLrUs1itIPvOObDMKnC4PO3z89DL7ywT4preCiWP3P9k5n7xOOQqIS1j3z77YAeqHzoNJ1st5OsUig51BEcMyJzJxqaCHHR+UjYYeEm39vJ3IXTzXHxQwTgyGmKVc2iCYemI+LVaHWHRy4e28gEPvcThEeNy+qwHdF X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1P190MB0317.EURP190.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230022)(4636009)(376002)(396003)(346002)(136003)(39830400003)(366004)(451199015)(36756003)(38100700002)(86362001)(38350700002)(2906002)(41300700001)(8936002)(4326008)(44832011)(5660300002)(7416002)(83380400001)(66946007)(478600001)(6486002)(66476007)(66556008)(316002)(54906003)(2616005)(110136005)(8676002)(107886003)(1076003)(6666004)(52116002)(6506007)(26005)(186003)(6512007);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 88ZUkP+/xJBFJYOQ1P5vFxypZv4Et7fu4X/DoRzua41khsaUYTR29PvpGqUEOx3Tn4dK2erCjVSRizUx1LQR/LgXfBF2NgEI8b/PmG4SSW8KEPkllg7s9lICQSuqkJzdZ3UOD0yPZtw+Et3nI8nS/MyOZyOYuLBLbT8WXbYhhsiMYG+ZC58nz151jaZDsKuMfezEhNuaTr85N6leNYApyKoe2V2UB6v5JfzkthxJXyphDMT03/40jjZNVHnfhpMi2i2Wbtk1XvQb4f287IML2TrNc5SX2lS7vmMl9O0Rioz78/oAS8+DmEJ1049qBlEM7I/d9suTEi+gCxtzR+M2hKyqyhTDPusVB3JKzf1Zh2TA1RhNQEeUrnK/uzcXjBi4C6z7kmYWYBtLn8kwiibtNjGfZILYa74cNsSLTc2H+JtVHuBe6yZg5cVAHjfCBoHR7kcSjkrts7KySFUWzYmI0X3wZoUHbMOPKJ9+kP49q14X47a0wOHEUPMrIdnsNA8eRTMP54gGh2YJPn8Nq7hTFWfZSw4dUS1SsGgXP8wsyhKtCrDTIePyqOc06n8hdtFie0+EgWKvxJN8kOZ76OjtS3l5AvxFNIsHqKY7Nmvmv5CvgH/Gy6i9lpFXlU7eYh4u2ZEsoxFkFZtht1TxR7LcKiLTnfMmttIv1HAJXo66X7stRuE25prfeO09LsktbJFWZtWqrMiu5PljeuCZGn+en3Uy293GZcUmJhhVUGk5yjfc+R43lURIGXPeioXCA5c+EHGcaHOgRAumnh+746mFzvq71lPEA0aTgWVebiGXhHelIfhwMXMans8JZpXymrtGTDd8tGCH0qSyJndcJdhB+IYD3JAzbzuBMLHkyc9KHuvTN1PNcDOF/Ae3vJrZ/7MFWXx2OIIA/NzOgnqocLt5d7USHVkn/lXQatihGy4glZMdqKWcttyuPzz+cUEhal7nkhVszXPGkcu4TOLOdF3VOgzSp8xOuZZzq7TiCnJ++PGAhkb0C8S/VIp/aC0wXOO4HOMyTiLggQmv0cOPOLp5vJ0Fa2IHaw3z8lf+CwWDwVjPe0kyw4dwko4BvTulrpapf7DSLamRD5W6K6MsmwAg9tAU+48fY9BB8IGmETfAB+pkyHhJMJU1Luwb4l2Fy/jp0TySXoH5P15NcQ4b70tcsDrLei/2NLo1+tzmnEZUxOw2mFaSwbxNwEV1Z+WVPw6yEStcVd/mCTN17Y3MTfxejhp7vOtEZBt33LTVNaEmQj3xEfGNOFPbN298rnyETamPmXkOzeRmZ+Rn7/eFX3STjTsWV25EgcpFlcN7PpWiImfJyxMIgK1u9pow5Ss1hoeK+98DrTYjuFm0owVukSDTDuAk7+d3JhW7umpFbW3oN6H67l1fmOvQIh6YGBEK9ECmWWUzbO1A9NPzjQEuH9647zJmppp0MVIBclO571oW0jqrLdev6gRs+zIKEDbrOq3FHHvVCNqjCw4XipP32JRu6orVi5l2kbLE4lvUcFXe1HgRuDKvewEdi4scPhhW2zUrRjDNk6cpfN0uRhS1K7EMm72lo8tP20HLR/MMBTtjSiFPY0pFtdMGlYCpAldCPKJNzstNl97Y9DIvK8wB2v0HZw== X-OriginatorOrg: plvision.eu X-MS-Exchange-CrossTenant-Network-Message-Id: ba06d64a-842c-4ae7-6165-08dad6afd538 X-MS-Exchange-CrossTenant-AuthSource: VI1P190MB0317.EURP190.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Dec 2022 10:59:51.2771 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 03707b74-30f3-46b6-a0e0-ff0a7438c9c4 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 9HiSZn03lR21RbbMBAfCkeErssuLgYO2ZzrCjIqmZh/DbMf1reaHU9i9F1DFqECxtB4Vs+wTAJLerXX2Ufc7anSYmhN/SCP3TlVDh1IKM3M= X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM8P190MB0980 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751371751940417370?= X-GMAIL-MSGID: =?utf-8?q?1751371751940417370?= |
Series |
mmc: xenon: Fix 2G DMA limitation on AC5 SoC
|
|
Commit Message
Vadym Kochan
Dec. 5, 2022, 10:59 a.m. UTC
There is a limitation on AC5 SoC that mmc controller can't have DMA access over 2G memory, so use SDMA with a bounce buffer. Swiotlb can't help because on arm64 arch it reserves memblock's at the end of the memory. Additionally set mask to 34 bit since on AC5 SoC RAM starts at 0x2_00000000. Co-developed-by: Elad Nachman <enachman@marvell.com> Signed-off-by: Elad Nachman <enachman@marvell.com> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> --- drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci-xenon.h | 3 ++- 2 files changed, 40 insertions(+), 1 deletion(-)
Comments
On Mon, Dec 5, 2022 at 12:00 PM Vadym Kochan <vadym.kochan@plvision.eu> wrote: > There is a limitation on AC5 SoC that mmc controller > can't have DMA access over 2G memory, That sounds like a pretty common problem when someone uses a 32bit address register in their DMA controller, or the integration engineer not connecting all address lines... :/ > so use SDMA with a bounce buffer. Swiotlb can't help because > on arm64 arch it reserves memblock's at the end of the memory. OK This: > Additionally set mask to 34 bit since on AC5 SoC RAM starts > at 0x2_00000000. (...) > +static int xenon_set_dma_mask(struct sdhci_host *host) > +{ > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > + struct mmc_host *mmc = host->mmc; > + struct device *dev = mmc_dev(mmc); > + > + if (priv->hw_version == XENON_AC5) { > + host->flags &= ~SDHCI_USE_64_BIT_DMA; > + > + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > + } > + > + return sdhci_set_dma_mask(host); > +} (...) > + .set_dma_mask = xenon_set_dma_mask, I don't know if is so good to assume the size and location of the SoC RAM like you do, that looks really fragile. Can't you check what physical RAM Linux actually think it has and where? You partly check it with meminfo below. > +static int xenon_ac5_probe(struct sdhci_host *host) > +{ > + struct sysinfo si; > + > + si_meminfo(&si); > + > + if ((si.totalram * si.mem_unit) > SZ_2G) This looks like a bug since you mention that the RAM does not start at 0x00000000 this means if the memory is 2G it will partly be at physical addresses above 2G.... > + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > + > + return 0; > +} Here you check how big the RAM is using meminfo (if the bug is fixed). But is this really a good solution? ADMA still works on the lower 2GB does it not? What you want is a new quirk that bounces only when you go above SZ_4G. There *is* SDHCI_QUIRK_32BIT_DMA_ADDR have you tried this? A 32bit DMA address is literally 4GB. I think all you need to do is set this flag for xenon. Yours, Linus Walleij
Hi, I would like to explain how this HW mechanism works: The lower 31-bits of the address placed in the ADMA is passed through the interconnect, and remapped to the base of the DDR. Hence only addressing of the lower 2GB of the DDR memory is supported for eMMC in this device family (AC5/X). So the quirk needs to kick in above 2GB of physical memory accessed from the base of the DDR. Since we cannot control the location of the various buffers passed in the Linux kernel via VFS to the eMMC driver, the only remedy is to kick in the quirk whenever buffer which point to the physical memory above 2GB * can * arrive to the eMMC driver, hence the quirk kicks in whenever a total physical memory size greater than 2GB is detected in the system. This is why a quirk which only kicks in above 4GB is not sufficient. Furthermore, SDHCI_QUIRK_32BIT_DMA_ADDR is checked in sdhci_prepare_data() as a way to disable DMA when the offset of the scatter-list DMA address is not 32-bit aligned. If the address is aligned, this quirk does not disable the DMA, and will not solve our problem. Hopefully this explains the motivation for the way the patch is written. FYI, Elad. -----Original Message----- From: Linus Walleij <linus.walleij@linaro.org> Sent: Wednesday, December 7, 2022 3:40 PM To: Vadym Kochan <vadym.kochan@plvision.eu> Cc: Hu Ziji <huziji@marvell.com>; Ulf Hansson <ulf.hansson@linaro.org>; Rob Herring <robh+dt@kernel.org>; Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>; Adrian Hunter <adrian.hunter@intel.com>; linux-mmc@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; Elad Nachman <enachman@marvell.com>; Chris Packham <chris.packham@alliedtelesis.co.nz> Subject: [EXT] Re: [PATCH v3 3/3] mmc: xenon: Fix 2G limitation on AC5 SoC External Email ---------------------------------------------------------------------- On Mon, Dec 5, 2022 at 12:00 PM Vadym Kochan <vadym.kochan@plvision.eu> wrote: > There is a limitation on AC5 SoC that mmc controller can't have DMA > access over 2G memory, That sounds like a pretty common problem when someone uses a 32bit address register in their DMA controller, or the integration engineer not connecting all address lines... :/ > so use SDMA with a bounce buffer. Swiotlb can't help because on arm64 > arch it reserves memblock's at the end of the memory. OK This: > Additionally set mask to 34 bit since on AC5 SoC RAM starts at > 0x2_00000000. (...) > +static int xenon_set_dma_mask(struct sdhci_host *host) { > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > + struct mmc_host *mmc = host->mmc; > + struct device *dev = mmc_dev(mmc); > + > + if (priv->hw_version == XENON_AC5) { > + host->flags &= ~SDHCI_USE_64_BIT_DMA; > + > + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > + } > + > + return sdhci_set_dma_mask(host); } (...) > + .set_dma_mask = xenon_set_dma_mask, I don't know if is so good to assume the size and location of the SoC RAM like you do, that looks really fragile. Can't you check what physical RAM Linux actually think it has and where? You partly check it with meminfo below. > +static int xenon_ac5_probe(struct sdhci_host *host) { > + struct sysinfo si; > + > + si_meminfo(&si); > + > + if ((si.totalram * si.mem_unit) > SZ_2G) This looks like a bug since you mention that the RAM does not start at 0x00000000 this means if the memory is 2G it will partly be at physical addresses above 2G.... > + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > + > + return 0; > +} Here you check how big the RAM is using meminfo (if the bug is fixed). But is this really a good solution? ADMA still works on the lower 2GB does it not? What you want is a new quirk that bounces only when you go above SZ_4G. There *is* SDHCI_QUIRK_32BIT_DMA_ADDR have you tried this? A 32bit DMA address is literally 4GB. I think all you need to do is set this flag for xenon. Yours, Linus Walleij
Hi Elad, I get it, I think. I was a bit confused by the 3G/4G terminology. On Thu, Dec 8, 2022 at 11:20 AM Elad Nachman <enachman@marvell.com> wrote: > The lower 31-bits of the address placed in the ADMA is passed through the interconnect, and remapped to the base of the DDR. > > Hence only addressing of the lower 2GB of the DDR memory is supported for eMMC in this device family (AC5/X). > > So the quirk needs to kick in above 2GB of physical memory accessed from the base of the DDR. How "clever" to skip bit 32. This should be in the patch description. > This is why a quirk which only kicks in above 4GB is not sufficient. So the author of the patch should create a new quirk that kicks in above 2GB, devised to be similar in style of the 4GB quirk we already have. > Furthermore, SDHCI_QUIRK_32BIT_DMA_ADDR is checked in sdhci_prepare_data() as a way to > disable DMA when the offset of the scatter-list DMA address is not 32-bit aligned. If the address is > aligned, this quirk does not disable the DMA, and will not solve our problem. That's right. Let's just create a new quirk: SDHCI_QUIRK_31BIT_DMA_ROOF Define the semantics such that this will allow DMA for buffers that are below the 31st bit, but does not have the semantics to limit scatter-gather buffers to be 32-bit aligned. Yours, Linus Walleij
On 5/12/22 12:59, Vadym Kochan wrote: > There is a limitation on AC5 SoC that mmc controller > can't have DMA access over 2G memory, so use SDMA with > a bounce buffer. Swiotlb can't help because on arm64 arch > it reserves memblock's at the end of the memory. > > Additionally set mask to 34 bit since on AC5 SoC RAM starts > at 0x2_00000000. Can you explain more about how a 34-bit DMA mask works when SDMA only supports 32-bit addresses? > > Co-developed-by: Elad Nachman <enachman@marvell.com> > Signed-off-by: Elad Nachman <enachman@marvell.com> > Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> > --- > drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ > drivers/mmc/host/sdhci-xenon.h | 3 ++- > 2 files changed, 40 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c > index 08e838400b52..5f3db0425674 100644 > --- a/drivers/mmc/host/sdhci-xenon.c > +++ b/drivers/mmc/host/sdhci-xenon.c > @@ -13,7 +13,9 @@ > > #include <linux/acpi.h> > #include <linux/delay.h> > +#include <linux/dma-mapping.h> > #include <linux/ktime.h> > +#include <linux/mm.h> > #include <linux/module.h> > #include <linux/of.h> > #include <linux/pm.h> > @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) > return pltfm_host->clock; > } > > +static int xenon_set_dma_mask(struct sdhci_host *host) > +{ > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > + struct mmc_host *mmc = host->mmc; > + struct device *dev = mmc_dev(mmc); > + > + if (priv->hw_version == XENON_AC5) { > + host->flags &= ~SDHCI_USE_64_BIT_DMA; > + > + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > + } > + > + return sdhci_set_dma_mask(host); > +} > + > static const struct sdhci_ops sdhci_xenon_ops = { > .voltage_switch = xenon_voltage_switch, > .set_clock = sdhci_set_clock, > @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { > .reset = xenon_reset, > .set_uhs_signaling = xenon_set_uhs_signaling, > .get_max_clock = xenon_get_max_clock, > + .set_dma_mask = xenon_set_dma_mask, > }; > > static const struct sdhci_pltfm_data sdhci_xenon_pdata = { > @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) > xenon_disable_sdhc(host, sdhc_id); > } > > +static int xenon_ac5_probe(struct sdhci_host *host) > +{ > + struct sysinfo si; > + > + si_meminfo(&si); > + > + if ((si.totalram * si.mem_unit) > SZ_2G) > + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > + > + return 0; > +} > + > static int xenon_probe(struct platform_device *pdev) > { > struct sdhci_pltfm_host *pltfm_host; > @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) > } > } > > + if (priv->hw_version == XENON_AC5) { > + err = xenon_ac5_probe(host); > + if (err) > + goto err_clk_axi; > + } > + > err = mmc_of_parse(host->mmc); > if (err) > goto err_clk_axi; > @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { > { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, > { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, > { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, > + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, > {} > }; > MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); > diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h > index 3e9c6c908a79..0460d97aad26 100644 > --- a/drivers/mmc/host/sdhci-xenon.h > +++ b/drivers/mmc/host/sdhci-xenon.h > @@ -57,7 +57,8 @@ enum xenon_variant { > XENON_A3700, > XENON_AP806, > XENON_AP807, > - XENON_CP110 > + XENON_CP110, > + XENON_AC5 > }; > > struct xenon_priv {
Hi Adrian, On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > On 5/12/22 12:59, Vadym Kochan wrote: > > There is a limitation on AC5 SoC that mmc controller > > can't have DMA access over 2G memory, so use SDMA with > > a bounce buffer. Swiotlb can't help because on arm64 arch > > it reserves memblock's at the end of the memory. > > > > Additionally set mask to 34 bit since on AC5 SoC RAM starts > > at 0x2_00000000. > > Can you explain more about how a 34-bit DMA mask works when > SDMA only supports 32-bit addresses? > So, after I set > > + host->flags &= ~SDHCI_USE_64_BIT_DMA; then sdhc core sets mask to 32 bit, but then dma_map fails to map bounce buffer because the base address is higher than 32bit - 0x2_00000000, and 34bit mask fixed it. > > > > Co-developed-by: Elad Nachman <enachman@marvell.com> > > Signed-off-by: Elad Nachman <enachman@marvell.com> > > Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> > > --- > > drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ > > drivers/mmc/host/sdhci-xenon.h | 3 ++- > > 2 files changed, 40 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c > > index 08e838400b52..5f3db0425674 100644 > > --- a/drivers/mmc/host/sdhci-xenon.c > > +++ b/drivers/mmc/host/sdhci-xenon.c > > @@ -13,7 +13,9 @@ > > > > #include <linux/acpi.h> > > #include <linux/delay.h> > > +#include <linux/dma-mapping.h> > > #include <linux/ktime.h> > > +#include <linux/mm.h> > > #include <linux/module.h> > > #include <linux/of.h> > > #include <linux/pm.h> > > @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) > > return pltfm_host->clock; > > } > > > > +static int xenon_set_dma_mask(struct sdhci_host *host) > > +{ > > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > > + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > > + struct mmc_host *mmc = host->mmc; > > + struct device *dev = mmc_dev(mmc); > > + > > + if (priv->hw_version == XENON_AC5) { > > + host->flags &= ~SDHCI_USE_64_BIT_DMA; > > + > > + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > > + } > > + > > + return sdhci_set_dma_mask(host); > > +} > > + > > static const struct sdhci_ops sdhci_xenon_ops = { > > .voltage_switch = xenon_voltage_switch, > > .set_clock = sdhci_set_clock, > > @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { > > .reset = xenon_reset, > > .set_uhs_signaling = xenon_set_uhs_signaling, > > .get_max_clock = xenon_get_max_clock, > > + .set_dma_mask = xenon_set_dma_mask, > > }; > > > > static const struct sdhci_pltfm_data sdhci_xenon_pdata = { > > @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) > > xenon_disable_sdhc(host, sdhc_id); > > } > > > > +static int xenon_ac5_probe(struct sdhci_host *host) > > +{ > > + struct sysinfo si; > > + > > + si_meminfo(&si); > > + > > + if ((si.totalram * si.mem_unit) > SZ_2G) > > + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > > + > > + return 0; > > +} > > + > > static int xenon_probe(struct platform_device *pdev) > > { > > struct sdhci_pltfm_host *pltfm_host; > > @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) > > } > > } > > > > + if (priv->hw_version == XENON_AC5) { > > + err = xenon_ac5_probe(host); > > + if (err) > > + goto err_clk_axi; > > + } > > + > > err = mmc_of_parse(host->mmc); > > if (err) > > goto err_clk_axi; > > @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { > > { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, > > { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, > > { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, > > + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, > > {} > > }; > > MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); > > diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h > > index 3e9c6c908a79..0460d97aad26 100644 > > --- a/drivers/mmc/host/sdhci-xenon.h > > +++ b/drivers/mmc/host/sdhci-xenon.h > > @@ -57,7 +57,8 @@ enum xenon_variant { > > XENON_A3700, > > XENON_AP806, > > XENON_AP807, > > - XENON_CP110 > > + XENON_CP110, > > + XENON_AC5 > > }; > > > > struct xenon_priv { > Regards,
On 9/12/22 13:39, Vadym Kochan wrote: > Hi Adrian, > > On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >> On 5/12/22 12:59, Vadym Kochan wrote: >>> There is a limitation on AC5 SoC that mmc controller >>> can't have DMA access over 2G memory, so use SDMA with >>> a bounce buffer. Swiotlb can't help because on arm64 arch >>> it reserves memblock's at the end of the memory. >>> >>> Additionally set mask to 34 bit since on AC5 SoC RAM starts >>> at 0x2_00000000. >> >> Can you explain more about how a 34-bit DMA mask works when >> SDMA only supports 32-bit addresses? >> > > So, after I set > >>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > > then sdhc core sets mask to 32 bit, but then dma_map fails to map > bounce buffer because the base address is higher than 32bit - 0x2_00000000, > and 34bit mask fixed it. What happens if the bounce buffer gets mapped in the range 0x1_00000000 to 0x1_ffffffff ? > >>> >>> Co-developed-by: Elad Nachman <enachman@marvell.com> >>> Signed-off-by: Elad Nachman <enachman@marvell.com> >>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> >>> --- >>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ >>> drivers/mmc/host/sdhci-xenon.h | 3 ++- >>> 2 files changed, 40 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >>> index 08e838400b52..5f3db0425674 100644 >>> --- a/drivers/mmc/host/sdhci-xenon.c >>> +++ b/drivers/mmc/host/sdhci-xenon.c >>> @@ -13,7 +13,9 @@ >>> >>> #include <linux/acpi.h> >>> #include <linux/delay.h> >>> +#include <linux/dma-mapping.h> >>> #include <linux/ktime.h> >>> +#include <linux/mm.h> >>> #include <linux/module.h> >>> #include <linux/of.h> >>> #include <linux/pm.h> >>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) >>> return pltfm_host->clock; >>> } >>> >>> +static int xenon_set_dma_mask(struct sdhci_host *host) >>> +{ >>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >>> + struct mmc_host *mmc = host->mmc; >>> + struct device *dev = mmc_dev(mmc); >>> + >>> + if (priv->hw_version == XENON_AC5) { >>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>> + >>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); >>> + } >>> + >>> + return sdhci_set_dma_mask(host); >>> +} >>> + >>> static const struct sdhci_ops sdhci_xenon_ops = { >>> .voltage_switch = xenon_voltage_switch, >>> .set_clock = sdhci_set_clock, >>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { >>> .reset = xenon_reset, >>> .set_uhs_signaling = xenon_set_uhs_signaling, >>> .get_max_clock = xenon_get_max_clock, >>> + .set_dma_mask = xenon_set_dma_mask, >>> }; >>> >>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { >>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) >>> xenon_disable_sdhc(host, sdhc_id); >>> } >>> >>> +static int xenon_ac5_probe(struct sdhci_host *host) >>> +{ >>> + struct sysinfo si; >>> + >>> + si_meminfo(&si); >>> + >>> + if ((si.totalram * si.mem_unit) > SZ_2G) >>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; >>> + >>> + return 0; >>> +} >>> + >>> static int xenon_probe(struct platform_device *pdev) >>> { >>> struct sdhci_pltfm_host *pltfm_host; >>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) >>> } >>> } >>> >>> + if (priv->hw_version == XENON_AC5) { >>> + err = xenon_ac5_probe(host); >>> + if (err) >>> + goto err_clk_axi; >>> + } >>> + >>> err = mmc_of_parse(host->mmc); >>> if (err) >>> goto err_clk_axi; >>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { >>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, >>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, >>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, >>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, >>> {} >>> }; >>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); >>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >>> index 3e9c6c908a79..0460d97aad26 100644 >>> --- a/drivers/mmc/host/sdhci-xenon.h >>> +++ b/drivers/mmc/host/sdhci-xenon.h >>> @@ -57,7 +57,8 @@ enum xenon_variant { >>> XENON_A3700, >>> XENON_AP806, >>> XENON_AP807, >>> - XENON_CP110 >>> + XENON_CP110, >>> + XENON_AC5 >>> }; >>> >>> struct xenon_priv { >> > > Regards,
Hi Adrian, On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > On 9/12/22 13:39, Vadym Kochan wrote: > > Hi Adrian, > > > > On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >> On 5/12/22 12:59, Vadym Kochan wrote: > >>> There is a limitation on AC5 SoC that mmc controller > >>> can't have DMA access over 2G memory, so use SDMA with > >>> a bounce buffer. Swiotlb can't help because on arm64 arch > >>> it reserves memblock's at the end of the memory. > >>> > >>> Additionally set mask to 34 bit since on AC5 SoC RAM starts > >>> at 0x2_00000000. > >> > >> Can you explain more about how a 34-bit DMA mask works when > >> SDMA only supports 32-bit addresses? > >> > > > > So, after I set > > > >>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > > > > then sdhc core sets mask to 32 bit, but then dma_map fails to map > > bounce buffer because the base address is higher than 32bit - 0x2_00000000, > > and 34bit mask fixed it. > > What happens if the bounce buffer gets mapped in the range > 0x1_00000000 to 0x1_ffffffff ? > From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce buffer can be mapped in the range 0x2_00000000..0x2_ffffffff > > > >>> > >>> Co-developed-by: Elad Nachman <enachman@marvell.com> > >>> Signed-off-by: Elad Nachman <enachman@marvell.com> > >>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> > >>> --- > >>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ > >>> drivers/mmc/host/sdhci-xenon.h | 3 ++- > >>> 2 files changed, 40 insertions(+), 1 deletion(-) > >>> > >>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c > >>> index 08e838400b52..5f3db0425674 100644 > >>> --- a/drivers/mmc/host/sdhci-xenon.c > >>> +++ b/drivers/mmc/host/sdhci-xenon.c > >>> @@ -13,7 +13,9 @@ > >>> > >>> #include <linux/acpi.h> > >>> #include <linux/delay.h> > >>> +#include <linux/dma-mapping.h> > >>> #include <linux/ktime.h> > >>> +#include <linux/mm.h> > >>> #include <linux/module.h> > >>> #include <linux/of.h> > >>> #include <linux/pm.h> > >>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) > >>> return pltfm_host->clock; > >>> } > >>> > >>> +static int xenon_set_dma_mask(struct sdhci_host *host) > >>> +{ > >>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > >>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > >>> + struct mmc_host *mmc = host->mmc; > >>> + struct device *dev = mmc_dev(mmc); > >>> + > >>> + if (priv->hw_version == XENON_AC5) { > >>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > >>> + > >>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > >>> + } > >>> + > >>> + return sdhci_set_dma_mask(host); > >>> +} > >>> + > >>> static const struct sdhci_ops sdhci_xenon_ops = { > >>> .voltage_switch = xenon_voltage_switch, > >>> .set_clock = sdhci_set_clock, > >>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { > >>> .reset = xenon_reset, > >>> .set_uhs_signaling = xenon_set_uhs_signaling, > >>> .get_max_clock = xenon_get_max_clock, > >>> + .set_dma_mask = xenon_set_dma_mask, > >>> }; > >>> > >>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { > >>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) > >>> xenon_disable_sdhc(host, sdhc_id); > >>> } > >>> > >>> +static int xenon_ac5_probe(struct sdhci_host *host) > >>> +{ > >>> + struct sysinfo si; > >>> + > >>> + si_meminfo(&si); > >>> + > >>> + if ((si.totalram * si.mem_unit) > SZ_2G) > >>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > >>> + > >>> + return 0; > >>> +} > >>> + > >>> static int xenon_probe(struct platform_device *pdev) > >>> { > >>> struct sdhci_pltfm_host *pltfm_host; > >>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) > >>> } > >>> } > >>> > >>> + if (priv->hw_version == XENON_AC5) { > >>> + err = xenon_ac5_probe(host); > >>> + if (err) > >>> + goto err_clk_axi; > >>> + } > >>> + > >>> err = mmc_of_parse(host->mmc); > >>> if (err) > >>> goto err_clk_axi; > >>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { > >>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, > >>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, > >>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, > >>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, > >>> {} > >>> }; > >>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); > >>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h > >>> index 3e9c6c908a79..0460d97aad26 100644 > >>> --- a/drivers/mmc/host/sdhci-xenon.h > >>> +++ b/drivers/mmc/host/sdhci-xenon.h > >>> @@ -57,7 +57,8 @@ enum xenon_variant { > >>> XENON_A3700, > >>> XENON_AP806, > >>> XENON_AP807, > >>> - XENON_CP110 > >>> + XENON_CP110, > >>> + XENON_AC5 > >>> }; > >>> > >>> struct xenon_priv { > >> > > > > Regards, >
On 9/12/22 14:10, Vadym Kochan wrote: > Hi Adrian, > > On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >> On 9/12/22 13:39, Vadym Kochan wrote: >>> Hi Adrian, >>> >>> On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>> On 5/12/22 12:59, Vadym Kochan wrote: >>>>> There is a limitation on AC5 SoC that mmc controller >>>>> can't have DMA access over 2G memory, so use SDMA with >>>>> a bounce buffer. Swiotlb can't help because on arm64 arch >>>>> it reserves memblock's at the end of the memory. >>>>> >>>>> Additionally set mask to 34 bit since on AC5 SoC RAM starts >>>>> at 0x2_00000000. >>>> >>>> Can you explain more about how a 34-bit DMA mask works when >>>> SDMA only supports 32-bit addresses? >>>> >>> >>> So, after I set >>> >>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>> >>> then sdhc core sets mask to 32 bit, but then dma_map fails to map >>> bounce buffer because the base address is higher than 32bit - 0x2_00000000, >>> and 34bit mask fixed it. >> >> What happens if the bounce buffer gets mapped in the range >> 0x1_00000000 to 0x1_ffffffff ? >> > > From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce > buffer can be mapped in the range 0x2_00000000..0x2_ffffffff Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? Isn't that also in DMA_BIT_MASK(34) > >>> >>>>> >>>>> Co-developed-by: Elad Nachman <enachman@marvell.com> >>>>> Signed-off-by: Elad Nachman <enachman@marvell.com> >>>>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> >>>>> --- >>>>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ >>>>> drivers/mmc/host/sdhci-xenon.h | 3 ++- >>>>> 2 files changed, 40 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >>>>> index 08e838400b52..5f3db0425674 100644 >>>>> --- a/drivers/mmc/host/sdhci-xenon.c >>>>> +++ b/drivers/mmc/host/sdhci-xenon.c >>>>> @@ -13,7 +13,9 @@ >>>>> >>>>> #include <linux/acpi.h> >>>>> #include <linux/delay.h> >>>>> +#include <linux/dma-mapping.h> >>>>> #include <linux/ktime.h> >>>>> +#include <linux/mm.h> >>>>> #include <linux/module.h> >>>>> #include <linux/of.h> >>>>> #include <linux/pm.h> >>>>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) >>>>> return pltfm_host->clock; >>>>> } >>>>> >>>>> +static int xenon_set_dma_mask(struct sdhci_host *host) >>>>> +{ >>>>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >>>>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >>>>> + struct mmc_host *mmc = host->mmc; >>>>> + struct device *dev = mmc_dev(mmc); >>>>> + >>>>> + if (priv->hw_version == XENON_AC5) { >>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>>>> + >>>>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); >>>>> + } >>>>> + >>>>> + return sdhci_set_dma_mask(host); >>>>> +} >>>>> + >>>>> static const struct sdhci_ops sdhci_xenon_ops = { >>>>> .voltage_switch = xenon_voltage_switch, >>>>> .set_clock = sdhci_set_clock, >>>>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { >>>>> .reset = xenon_reset, >>>>> .set_uhs_signaling = xenon_set_uhs_signaling, >>>>> .get_max_clock = xenon_get_max_clock, >>>>> + .set_dma_mask = xenon_set_dma_mask, >>>>> }; >>>>> >>>>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { >>>>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) >>>>> xenon_disable_sdhc(host, sdhc_id); >>>>> } >>>>> >>>>> +static int xenon_ac5_probe(struct sdhci_host *host) >>>>> +{ >>>>> + struct sysinfo si; >>>>> + >>>>> + si_meminfo(&si); >>>>> + >>>>> + if ((si.totalram * si.mem_unit) > SZ_2G) >>>>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> static int xenon_probe(struct platform_device *pdev) >>>>> { >>>>> struct sdhci_pltfm_host *pltfm_host; >>>>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) >>>>> } >>>>> } >>>>> >>>>> + if (priv->hw_version == XENON_AC5) { >>>>> + err = xenon_ac5_probe(host); >>>>> + if (err) >>>>> + goto err_clk_axi; >>>>> + } >>>>> + >>>>> err = mmc_of_parse(host->mmc); >>>>> if (err) >>>>> goto err_clk_axi; >>>>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { >>>>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, >>>>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, >>>>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, >>>>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, >>>>> {} >>>>> }; >>>>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); >>>>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >>>>> index 3e9c6c908a79..0460d97aad26 100644 >>>>> --- a/drivers/mmc/host/sdhci-xenon.h >>>>> +++ b/drivers/mmc/host/sdhci-xenon.h >>>>> @@ -57,7 +57,8 @@ enum xenon_variant { >>>>> XENON_A3700, >>>>> XENON_AP806, >>>>> XENON_AP807, >>>>> - XENON_CP110 >>>>> + XENON_CP110, >>>>> + XENON_AC5 >>>>> }; >>>>> >>>>> struct xenon_priv { >>>> >>> >>> Regards, >>
On Fri, 9 Dec 2022 14:13:06 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > On 9/12/22 14:10, Vadym Kochan wrote: > > Hi Adrian, > > > > On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >> On 9/12/22 13:39, Vadym Kochan wrote: > >>> Hi Adrian, > >>> > >>> On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >>>> On 5/12/22 12:59, Vadym Kochan wrote: > >>>>> There is a limitation on AC5 SoC that mmc controller > >>>>> can't have DMA access over 2G memory, so use SDMA with > >>>>> a bounce buffer. Swiotlb can't help because on arm64 arch > >>>>> it reserves memblock's at the end of the memory. > >>>>> > >>>>> Additionally set mask to 34 bit since on AC5 SoC RAM starts > >>>>> at 0x2_00000000. > >>>> > >>>> Can you explain more about how a 34-bit DMA mask works when > >>>> SDMA only supports 32-bit addresses? > >>>> > >>> > >>> So, after I set > >>> > >>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > >>> > >>> then sdhc core sets mask to 32 bit, but then dma_map fails to map > >>> bounce buffer because the base address is higher than 32bit - 0x2_00000000, > >>> and 34bit mask fixed it. > >> > >> What happens if the bounce buffer gets mapped in the range > >> 0x1_00000000 to 0x1_ffffffff ? > >> > > > > From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce > > buffer can be mapped in the range 0x2_00000000..0x2_ffffffff > > Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? > Isn't that also in DMA_BIT_MASK(34) Yes, you are right. > > > > >>> > >>>>> > >>>>> Co-developed-by: Elad Nachman <enachman@marvell.com> > >>>>> Signed-off-by: Elad Nachman <enachman@marvell.com> > >>>>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> > >>>>> --- > >>>>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ > >>>>> drivers/mmc/host/sdhci-xenon.h | 3 ++- > >>>>> 2 files changed, 40 insertions(+), 1 deletion(-) > >>>>> > >>>>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c > >>>>> index 08e838400b52..5f3db0425674 100644 > >>>>> --- a/drivers/mmc/host/sdhci-xenon.c > >>>>> +++ b/drivers/mmc/host/sdhci-xenon.c > >>>>> @@ -13,7 +13,9 @@ > >>>>> > >>>>> #include <linux/acpi.h> > >>>>> #include <linux/delay.h> > >>>>> +#include <linux/dma-mapping.h> > >>>>> #include <linux/ktime.h> > >>>>> +#include <linux/mm.h> > >>>>> #include <linux/module.h> > >>>>> #include <linux/of.h> > >>>>> #include <linux/pm.h> > >>>>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) > >>>>> return pltfm_host->clock; > >>>>> } > >>>>> > >>>>> +static int xenon_set_dma_mask(struct sdhci_host *host) > >>>>> +{ > >>>>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > >>>>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > >>>>> + struct mmc_host *mmc = host->mmc; > >>>>> + struct device *dev = mmc_dev(mmc); > >>>>> + > >>>>> + if (priv->hw_version == XENON_AC5) { > >>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > >>>>> + > >>>>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > >>>>> + } > >>>>> + > >>>>> + return sdhci_set_dma_mask(host); > >>>>> +} > >>>>> + > >>>>> static const struct sdhci_ops sdhci_xenon_ops = { > >>>>> .voltage_switch = xenon_voltage_switch, > >>>>> .set_clock = sdhci_set_clock, > >>>>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { > >>>>> .reset = xenon_reset, > >>>>> .set_uhs_signaling = xenon_set_uhs_signaling, > >>>>> .get_max_clock = xenon_get_max_clock, > >>>>> + .set_dma_mask = xenon_set_dma_mask, > >>>>> }; > >>>>> > >>>>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { > >>>>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) > >>>>> xenon_disable_sdhc(host, sdhc_id); > >>>>> } > >>>>> > >>>>> +static int xenon_ac5_probe(struct sdhci_host *host) > >>>>> +{ > >>>>> + struct sysinfo si; > >>>>> + > >>>>> + si_meminfo(&si); > >>>>> + > >>>>> + if ((si.totalram * si.mem_unit) > SZ_2G) > >>>>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > >>>>> + > >>>>> + return 0; > >>>>> +} > >>>>> + > >>>>> static int xenon_probe(struct platform_device *pdev) > >>>>> { > >>>>> struct sdhci_pltfm_host *pltfm_host; > >>>>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) > >>>>> } > >>>>> } > >>>>> > >>>>> + if (priv->hw_version == XENON_AC5) { > >>>>> + err = xenon_ac5_probe(host); > >>>>> + if (err) > >>>>> + goto err_clk_axi; > >>>>> + } > >>>>> + > >>>>> err = mmc_of_parse(host->mmc); > >>>>> if (err) > >>>>> goto err_clk_axi; > >>>>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { > >>>>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, > >>>>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, > >>>>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, > >>>>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, > >>>>> {} > >>>>> }; > >>>>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); > >>>>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h > >>>>> index 3e9c6c908a79..0460d97aad26 100644 > >>>>> --- a/drivers/mmc/host/sdhci-xenon.h > >>>>> +++ b/drivers/mmc/host/sdhci-xenon.h > >>>>> @@ -57,7 +57,8 @@ enum xenon_variant { > >>>>> XENON_A3700, > >>>>> XENON_AP806, > >>>>> XENON_AP807, > >>>>> - XENON_CP110 > >>>>> + XENON_CP110, > >>>>> + XENON_AC5 > >>>>> }; > >>>>> > >>>>> struct xenon_priv { > >>>> > >>> > >>> Regards, > >> >
On 9/12/22 15:27, Vadym Kochan wrote: > On Fri, 9 Dec 2022 14:13:06 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >> On 9/12/22 14:10, Vadym Kochan wrote: >>> Hi Adrian, >>> >>> On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>> On 9/12/22 13:39, Vadym Kochan wrote: >>>>> Hi Adrian, >>>>> >>>>> On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>>>> On 5/12/22 12:59, Vadym Kochan wrote: >>>>>>> There is a limitation on AC5 SoC that mmc controller >>>>>>> can't have DMA access over 2G memory, so use SDMA with >>>>>>> a bounce buffer. Swiotlb can't help because on arm64 arch >>>>>>> it reserves memblock's at the end of the memory. >>>>>>> >>>>>>> Additionally set mask to 34 bit since on AC5 SoC RAM starts >>>>>>> at 0x2_00000000. >>>>>> >>>>>> Can you explain more about how a 34-bit DMA mask works when >>>>>> SDMA only supports 32-bit addresses? >>>>>> >>>>> >>>>> So, after I set >>>>> >>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>>>> >>>>> then sdhc core sets mask to 32 bit, but then dma_map fails to map >>>>> bounce buffer because the base address is higher than 32bit - 0x2_00000000, >>>>> and 34bit mask fixed it. >>>> >>>> What happens if the bounce buffer gets mapped in the range >>>> 0x1_00000000 to 0x1_ffffffff ? >>>> >>> >>> From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce >>> buffer can be mapped in the range 0x2_00000000..0x2_ffffffff >> >> Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? >> Isn't that also in DMA_BIT_MASK(34) > > Yes, you are right. So it would fail in that case? Is it possible to use devicetree reserved memory or some such, to set aside 64k for the bounce buffer DMA mapping? > >> >>> >>>>> >>>>>>> >>>>>>> Co-developed-by: Elad Nachman <enachman@marvell.com> >>>>>>> Signed-off-by: Elad Nachman <enachman@marvell.com> >>>>>>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> >>>>>>> --- >>>>>>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ >>>>>>> drivers/mmc/host/sdhci-xenon.h | 3 ++- >>>>>>> 2 files changed, 40 insertions(+), 1 deletion(-) >>>>>>> >>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >>>>>>> index 08e838400b52..5f3db0425674 100644 >>>>>>> --- a/drivers/mmc/host/sdhci-xenon.c >>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.c >>>>>>> @@ -13,7 +13,9 @@ >>>>>>> >>>>>>> #include <linux/acpi.h> >>>>>>> #include <linux/delay.h> >>>>>>> +#include <linux/dma-mapping.h> >>>>>>> #include <linux/ktime.h> >>>>>>> +#include <linux/mm.h> >>>>>>> #include <linux/module.h> >>>>>>> #include <linux/of.h> >>>>>>> #include <linux/pm.h> >>>>>>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) >>>>>>> return pltfm_host->clock; >>>>>>> } >>>>>>> >>>>>>> +static int xenon_set_dma_mask(struct sdhci_host *host) >>>>>>> +{ >>>>>>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >>>>>>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >>>>>>> + struct mmc_host *mmc = host->mmc; >>>>>>> + struct device *dev = mmc_dev(mmc); >>>>>>> + >>>>>>> + if (priv->hw_version == XENON_AC5) { >>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>>>>>> + >>>>>>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); >>>>>>> + } >>>>>>> + >>>>>>> + return sdhci_set_dma_mask(host); >>>>>>> +} >>>>>>> + >>>>>>> static const struct sdhci_ops sdhci_xenon_ops = { >>>>>>> .voltage_switch = xenon_voltage_switch, >>>>>>> .set_clock = sdhci_set_clock, >>>>>>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { >>>>>>> .reset = xenon_reset, >>>>>>> .set_uhs_signaling = xenon_set_uhs_signaling, >>>>>>> .get_max_clock = xenon_get_max_clock, >>>>>>> + .set_dma_mask = xenon_set_dma_mask, >>>>>>> }; >>>>>>> >>>>>>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { >>>>>>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) >>>>>>> xenon_disable_sdhc(host, sdhc_id); >>>>>>> } >>>>>>> >>>>>>> +static int xenon_ac5_probe(struct sdhci_host *host) >>>>>>> +{ >>>>>>> + struct sysinfo si; >>>>>>> + >>>>>>> + si_meminfo(&si); >>>>>>> + >>>>>>> + if ((si.totalram * si.mem_unit) > SZ_2G) >>>>>>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; >>>>>>> + >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> static int xenon_probe(struct platform_device *pdev) >>>>>>> { >>>>>>> struct sdhci_pltfm_host *pltfm_host; >>>>>>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) >>>>>>> } >>>>>>> } >>>>>>> >>>>>>> + if (priv->hw_version == XENON_AC5) { >>>>>>> + err = xenon_ac5_probe(host); >>>>>>> + if (err) >>>>>>> + goto err_clk_axi; >>>>>>> + } >>>>>>> + >>>>>>> err = mmc_of_parse(host->mmc); >>>>>>> if (err) >>>>>>> goto err_clk_axi; >>>>>>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { >>>>>>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, >>>>>>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, >>>>>>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, >>>>>>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, >>>>>>> {} >>>>>>> }; >>>>>>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); >>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >>>>>>> index 3e9c6c908a79..0460d97aad26 100644 >>>>>>> --- a/drivers/mmc/host/sdhci-xenon.h >>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.h >>>>>>> @@ -57,7 +57,8 @@ enum xenon_variant { >>>>>>> XENON_A3700, >>>>>>> XENON_AP806, >>>>>>> XENON_AP807, >>>>>>> - XENON_CP110 >>>>>>> + XENON_CP110, >>>>>>> + XENON_AC5 >>>>>>> }; >>>>>>> >>>>>>> struct xenon_priv { >>>>>> >>>>> >>>>> Regards, >>>> >>
Hi Adrian, On Mon, 12 Dec 2022 10:42:36 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > On 9/12/22 15:27, Vadym Kochan wrote: > > On Fri, 9 Dec 2022 14:13:06 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >> On 9/12/22 14:10, Vadym Kochan wrote: > >>> Hi Adrian, > >>> > >>> On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >>>> On 9/12/22 13:39, Vadym Kochan wrote: > >>>>> Hi Adrian, > >>>>> > >>>>> On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: > >>>>>> On 5/12/22 12:59, Vadym Kochan wrote: > >>>>>>> There is a limitation on AC5 SoC that mmc controller > >>>>>>> can't have DMA access over 2G memory, so use SDMA with > >>>>>>> a bounce buffer. Swiotlb can't help because on arm64 arch > >>>>>>> it reserves memblock's at the end of the memory. > >>>>>>> > >>>>>>> Additionally set mask to 34 bit since on AC5 SoC RAM starts > >>>>>>> at 0x2_00000000. > >>>>>> > >>>>>> Can you explain more about how a 34-bit DMA mask works when > >>>>>> SDMA only supports 32-bit addresses? > >>>>>> > >>>>> > >>>>> So, after I set > >>>>> > >>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > >>>>> > >>>>> then sdhc core sets mask to 32 bit, but then dma_map fails to map > >>>>> bounce buffer because the base address is higher than 32bit - 0x2_00000000, > >>>>> and 34bit mask fixed it. > >>>> > >>>> What happens if the bounce buffer gets mapped in the range > >>>> 0x1_00000000 to 0x1_ffffffff ? > >>>> > >>> > >>> From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce > >>> buffer can be mapped in the range 0x2_00000000..0x2_ffffffff > >> > >> Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? > >> Isn't that also in DMA_BIT_MASK(34) > > > > Yes, you are right. > > So it would fail in that case? Is it possible to use devicetree > reserved memory or some such, to set aside 64k for the bounce > buffer DMA mapping? > The main restriction is that only lower 2GB can be used for DMA. I already did send solution based on reserved memory, I can send it again in context of this series. Also what about the solution which Linus suggested ? [cut] Let's just create a new quirk: SDHCI_QUIRK_31BIT_DMA_ROOF Define the semantics such that this will allow DMA for buffers that are below the 31st bit, but does not have the semantics to limit scatter-gather buffers to be 32-bit aligned. [/cut] Thanks, > > > >> > >>> > >>>>> > >>>>>>> > >>>>>>> Co-developed-by: Elad Nachman <enachman@marvell.com> > >>>>>>> Signed-off-by: Elad Nachman <enachman@marvell.com> > >>>>>>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> > >>>>>>> --- > >>>>>>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ > >>>>>>> drivers/mmc/host/sdhci-xenon.h | 3 ++- > >>>>>>> 2 files changed, 40 insertions(+), 1 deletion(-) > >>>>>>> > >>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c > >>>>>>> index 08e838400b52..5f3db0425674 100644 > >>>>>>> --- a/drivers/mmc/host/sdhci-xenon.c > >>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.c > >>>>>>> @@ -13,7 +13,9 @@ > >>>>>>> > >>>>>>> #include <linux/acpi.h> > >>>>>>> #include <linux/delay.h> > >>>>>>> +#include <linux/dma-mapping.h> > >>>>>>> #include <linux/ktime.h> > >>>>>>> +#include <linux/mm.h> > >>>>>>> #include <linux/module.h> > >>>>>>> #include <linux/of.h> > >>>>>>> #include <linux/pm.h> > >>>>>>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) > >>>>>>> return pltfm_host->clock; > >>>>>>> } > >>>>>>> > >>>>>>> +static int xenon_set_dma_mask(struct sdhci_host *host) > >>>>>>> +{ > >>>>>>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > >>>>>>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); > >>>>>>> + struct mmc_host *mmc = host->mmc; > >>>>>>> + struct device *dev = mmc_dev(mmc); > >>>>>>> + > >>>>>>> + if (priv->hw_version == XENON_AC5) { > >>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; > >>>>>>> + > >>>>>>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); > >>>>>>> + } > >>>>>>> + > >>>>>>> + return sdhci_set_dma_mask(host); > >>>>>>> +} > >>>>>>> + > >>>>>>> static const struct sdhci_ops sdhci_xenon_ops = { > >>>>>>> .voltage_switch = xenon_voltage_switch, > >>>>>>> .set_clock = sdhci_set_clock, > >>>>>>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { > >>>>>>> .reset = xenon_reset, > >>>>>>> .set_uhs_signaling = xenon_set_uhs_signaling, > >>>>>>> .get_max_clock = xenon_get_max_clock, > >>>>>>> + .set_dma_mask = xenon_set_dma_mask, > >>>>>>> }; > >>>>>>> > >>>>>>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { > >>>>>>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) > >>>>>>> xenon_disable_sdhc(host, sdhc_id); > >>>>>>> } > >>>>>>> > >>>>>>> +static int xenon_ac5_probe(struct sdhci_host *host) > >>>>>>> +{ > >>>>>>> + struct sysinfo si; > >>>>>>> + > >>>>>>> + si_meminfo(&si); > >>>>>>> + > >>>>>>> + if ((si.totalram * si.mem_unit) > SZ_2G) > >>>>>>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; > >>>>>>> + > >>>>>>> + return 0; > >>>>>>> +} > >>>>>>> + > >>>>>>> static int xenon_probe(struct platform_device *pdev) > >>>>>>> { > >>>>>>> struct sdhci_pltfm_host *pltfm_host; > >>>>>>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) > >>>>>>> } > >>>>>>> } > >>>>>>> > >>>>>>> + if (priv->hw_version == XENON_AC5) { > >>>>>>> + err = xenon_ac5_probe(host); > >>>>>>> + if (err) > >>>>>>> + goto err_clk_axi; > >>>>>>> + } > >>>>>>> + > >>>>>>> err = mmc_of_parse(host->mmc); > >>>>>>> if (err) > >>>>>>> goto err_clk_axi; > >>>>>>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { > >>>>>>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, > >>>>>>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, > >>>>>>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, > >>>>>>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, > >>>>>>> {} > >>>>>>> }; > >>>>>>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); > >>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h > >>>>>>> index 3e9c6c908a79..0460d97aad26 100644 > >>>>>>> --- a/drivers/mmc/host/sdhci-xenon.h > >>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.h > >>>>>>> @@ -57,7 +57,8 @@ enum xenon_variant { > >>>>>>> XENON_A3700, > >>>>>>> XENON_AP806, > >>>>>>> XENON_AP807, > >>>>>>> - XENON_CP110 > >>>>>>> + XENON_CP110, > >>>>>>> + XENON_AC5 > >>>>>>> }; > >>>>>>> > >>>>>>> struct xenon_priv { > >>>>>> > >>>>> > >>>>> Regards, > >>>> > >> >
On 12/12/22 13:34, Vadym Kochan wrote: > Hi Adrian, > > On Mon, 12 Dec 2022 10:42:36 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >> On 9/12/22 15:27, Vadym Kochan wrote: >>> On Fri, 9 Dec 2022 14:13:06 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>> On 9/12/22 14:10, Vadym Kochan wrote: >>>>> Hi Adrian, >>>>> >>>>> On Fri, 9 Dec 2022 13:53:58 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>>>> On 9/12/22 13:39, Vadym Kochan wrote: >>>>>>> Hi Adrian, >>>>>>> >>>>>>> On Fri, 9 Dec 2022 09:23:05 +0200, Adrian Hunter <adrian.hunter@intel.com> wrote: >>>>>>>> On 5/12/22 12:59, Vadym Kochan wrote: >>>>>>>>> There is a limitation on AC5 SoC that mmc controller >>>>>>>>> can't have DMA access over 2G memory, so use SDMA with >>>>>>>>> a bounce buffer. Swiotlb can't help because on arm64 arch >>>>>>>>> it reserves memblock's at the end of the memory. >>>>>>>>> >>>>>>>>> Additionally set mask to 34 bit since on AC5 SoC RAM starts >>>>>>>>> at 0x2_00000000. >>>>>>>> >>>>>>>> Can you explain more about how a 34-bit DMA mask works when >>>>>>>> SDMA only supports 32-bit addresses? >>>>>>>> >>>>>>> >>>>>>> So, after I set >>>>>>> >>>>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>>>>>> >>>>>>> then sdhc core sets mask to 32 bit, but then dma_map fails to map >>>>>>> bounce buffer because the base address is higher than 32bit - 0x2_00000000, >>>>>>> and 34bit mask fixed it. >>>>>> >>>>>> What happens if the bounce buffer gets mapped in the range >>>>>> 0x1_00000000 to 0x1_ffffffff ? >>>>>> >>>>> >>>>> From my understanding, on the AC5 SoC RAM starts at 0x2_00000000 so the bounce >>>>> buffer can be mapped in the range 0x2_00000000..0x2_ffffffff >>>> >>>> Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? >>>> Isn't that also in DMA_BIT_MASK(34) >>> >>> Yes, you are right. >> >> So it would fail in that case? Is it possible to use devicetree >> reserved memory or some such, to set aside 64k for the bounce >> buffer DMA mapping? >> > > The main restriction is that only lower 2GB can be used for DMA. > > I already did send solution based on reserved memory, I can send it again in context of this series. > Also what about the solution which Linus suggested ? > > [cut] > > Let's just create a new quirk: > > SDHCI_QUIRK_31BIT_DMA_ROOF > > Define the semantics such that this will allow DMA for buffers that are below > the 31st bit, but does not have the semantics to limit scatter-gather buffers to > be 32-bit aligned. > > [/cut] Wouldn't that need to be done after DMA mapping? In the SDMA case, the bounce buffer would need to be checked only once and if wrong then it would be PIO-only for all requests. You probably don't need need a quirk for that since the check could be done at probe time. In the ADMA case the ADMA table would have to be checked also. And then after every dma_map_sg(). Seems a bit messy? > > Thanks, > >>> >>>> >>>>> >>>>>>> >>>>>>>>> >>>>>>>>> Co-developed-by: Elad Nachman <enachman@marvell.com> >>>>>>>>> Signed-off-by: Elad Nachman <enachman@marvell.com> >>>>>>>>> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu> >>>>>>>>> --- >>>>>>>>> drivers/mmc/host/sdhci-xenon.c | 38 ++++++++++++++++++++++++++++++++++ >>>>>>>>> drivers/mmc/host/sdhci-xenon.h | 3 ++- >>>>>>>>> 2 files changed, 40 insertions(+), 1 deletion(-) >>>>>>>>> >>>>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c >>>>>>>>> index 08e838400b52..5f3db0425674 100644 >>>>>>>>> --- a/drivers/mmc/host/sdhci-xenon.c >>>>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.c >>>>>>>>> @@ -13,7 +13,9 @@ >>>>>>>>> >>>>>>>>> #include <linux/acpi.h> >>>>>>>>> #include <linux/delay.h> >>>>>>>>> +#include <linux/dma-mapping.h> >>>>>>>>> #include <linux/ktime.h> >>>>>>>>> +#include <linux/mm.h> >>>>>>>>> #include <linux/module.h> >>>>>>>>> #include <linux/of.h> >>>>>>>>> #include <linux/pm.h> >>>>>>>>> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) >>>>>>>>> return pltfm_host->clock; >>>>>>>>> } >>>>>>>>> >>>>>>>>> +static int xenon_set_dma_mask(struct sdhci_host *host) >>>>>>>>> +{ >>>>>>>>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >>>>>>>>> + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); >>>>>>>>> + struct mmc_host *mmc = host->mmc; >>>>>>>>> + struct device *dev = mmc_dev(mmc); >>>>>>>>> + >>>>>>>>> + if (priv->hw_version == XENON_AC5) { >>>>>>>>> + host->flags &= ~SDHCI_USE_64_BIT_DMA; >>>>>>>>> + >>>>>>>>> + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); >>>>>>>>> + } >>>>>>>>> + >>>>>>>>> + return sdhci_set_dma_mask(host); >>>>>>>>> +} >>>>>>>>> + >>>>>>>>> static const struct sdhci_ops sdhci_xenon_ops = { >>>>>>>>> .voltage_switch = xenon_voltage_switch, >>>>>>>>> .set_clock = sdhci_set_clock, >>>>>>>>> @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { >>>>>>>>> .reset = xenon_reset, >>>>>>>>> .set_uhs_signaling = xenon_set_uhs_signaling, >>>>>>>>> .get_max_clock = xenon_get_max_clock, >>>>>>>>> + .set_dma_mask = xenon_set_dma_mask, >>>>>>>>> }; >>>>>>>>> >>>>>>>>> static const struct sdhci_pltfm_data sdhci_xenon_pdata = { >>>>>>>>> @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) >>>>>>>>> xenon_disable_sdhc(host, sdhc_id); >>>>>>>>> } >>>>>>>>> >>>>>>>>> +static int xenon_ac5_probe(struct sdhci_host *host) >>>>>>>>> +{ >>>>>>>>> + struct sysinfo si; >>>>>>>>> + >>>>>>>>> + si_meminfo(&si); >>>>>>>>> + >>>>>>>>> + if ((si.totalram * si.mem_unit) > SZ_2G) >>>>>>>>> + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; >>>>>>>>> + >>>>>>>>> + return 0; >>>>>>>>> +} >>>>>>>>> + >>>>>>>>> static int xenon_probe(struct platform_device *pdev) >>>>>>>>> { >>>>>>>>> struct sdhci_pltfm_host *pltfm_host; >>>>>>>>> @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) >>>>>>>>> } >>>>>>>>> } >>>>>>>>> >>>>>>>>> + if (priv->hw_version == XENON_AC5) { >>>>>>>>> + err = xenon_ac5_probe(host); >>>>>>>>> + if (err) >>>>>>>>> + goto err_clk_axi; >>>>>>>>> + } >>>>>>>>> + >>>>>>>>> err = mmc_of_parse(host->mmc); >>>>>>>>> if (err) >>>>>>>>> goto err_clk_axi; >>>>>>>>> @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { >>>>>>>>> { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, >>>>>>>>> { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, >>>>>>>>> { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, >>>>>>>>> + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, >>>>>>>>> {} >>>>>>>>> }; >>>>>>>>> MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); >>>>>>>>> diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h >>>>>>>>> index 3e9c6c908a79..0460d97aad26 100644 >>>>>>>>> --- a/drivers/mmc/host/sdhci-xenon.h >>>>>>>>> +++ b/drivers/mmc/host/sdhci-xenon.h >>>>>>>>> @@ -57,7 +57,8 @@ enum xenon_variant { >>>>>>>>> XENON_A3700, >>>>>>>>> XENON_AP806, >>>>>>>>> XENON_AP807, >>>>>>>>> - XENON_CP110 >>>>>>>>> + XENON_CP110, >>>>>>>>> + XENON_AC5 >>>>>>>>> }; >>>>>>>>> >>>>>>>>> struct xenon_priv { >>>>>>>> >>>>>>> >>>>>>> Regards, >>>>>> >>>> >>
On Mon, Dec 12, 2022 at 9:43 AM Adrian Hunter <adrian.hunter@intel.com> wrote: > >> Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? > >> Isn't that also in DMA_BIT_MASK(34) > > > > Yes, you are right. > > So it would fail in that case? Is it possible to use devicetree > reserved memory or some such, to set aside 64k for the bounce > buffer DMA mapping? Yups spot on, reserved-memory can be used along with the kernel CONFIG_DMA_CMA to achieve exactly this: Documentation/devicetree/bindings/reserved-memory/reserved-memory.yaml kernel/dma/Kconfig Yours, Linus Walleij
Hi Linus, Adrian, On Tue, 13 Dec 2022 10:16:57 +0100, Linus Walleij <linus.walleij@linaro.org> wrote: > On Mon, Dec 12, 2022 at 9:43 AM Adrian Hunter <adrian.hunter@intel.com> wrote: > > > >> Right but I guess I meant what about 0x3_00000000..0x3_ffffffff ? > > >> Isn't that also in DMA_BIT_MASK(34) > > > > > > Yes, you are right. > > > > So it would fail in that case? Is it possible to use devicetree > > reserved memory or some such, to set aside 64k for the bounce > > buffer DMA mapping? > > Yups spot on, reserved-memory can be used along with the kernel > CONFIG_DMA_CMA to achieve exactly this: > Documentation/devicetree/bindings/reserved-memory/reserved-memory.yaml > kernel/dma/Kconfig > > Yours, > Linus Walleij Just in case, here is an old series with reserved-memory solution: https://lore.kernel.org/lkml/20220806085818.9873-4-vadym.kochan@plvision.eu/T/ But, what about to start with PIO solution (which is conceptually easier solution) with checking on ram size and then develop better one ? Thanks,
On Mon, Dec 12, 2022 at 12:40 PM Vadym Kochan <vadym.kochan@plvision.eu> wrote: > The main restriction is that only lower 2GB can be used for DMA. > > I already did send solution based on reserved memory, I can send it again in context of this series. > Also what about the solution which Linus suggested ? > > [cut] > > Let's just create a new quirk: > > SDHCI_QUIRK_31BIT_DMA_ROOF > > Define the semantics such that this will allow DMA for buffers that are below > the 31st bit, but does not have the semantics to limit scatter-gather buffers to > be 32-bit aligned. > > [/cut] One does not exclude the other, so you could technically let buffers below 2^31 pass directly to the DMA engine, but bounce any request above that limit to a low memory bounce buffer. As Adrian points out there is also the code complexity question, the solution should be simple and elegant, if possible. I think always using a bounce buffer might be both nice and efficient. Yours, Linus Walleij
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 08e838400b52..5f3db0425674 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -13,7 +13,9 @@ #include <linux/acpi.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/ktime.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/of.h> #include <linux/pm.h> @@ -253,6 +255,22 @@ static unsigned int xenon_get_max_clock(struct sdhci_host *host) return pltfm_host->clock; } +static int xenon_set_dma_mask(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc_dev(mmc); + + if (priv->hw_version == XENON_AC5) { + host->flags &= ~SDHCI_USE_64_BIT_DMA; + + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); + } + + return sdhci_set_dma_mask(host); +} + static const struct sdhci_ops sdhci_xenon_ops = { .voltage_switch = xenon_voltage_switch, .set_clock = sdhci_set_clock, @@ -261,6 +279,7 @@ static const struct sdhci_ops sdhci_xenon_ops = { .reset = xenon_reset, .set_uhs_signaling = xenon_set_uhs_signaling, .get_max_clock = xenon_get_max_clock, + .set_dma_mask = xenon_set_dma_mask, }; static const struct sdhci_pltfm_data sdhci_xenon_pdata = { @@ -486,6 +505,18 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) xenon_disable_sdhc(host, sdhc_id); } +static int xenon_ac5_probe(struct sdhci_host *host) +{ + struct sysinfo si; + + si_meminfo(&si); + + if ((si.totalram * si.mem_unit) > SZ_2G) + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + + return 0; +} + static int xenon_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -533,6 +564,12 @@ static int xenon_probe(struct platform_device *pdev) } } + if (priv->hw_version == XENON_AC5) { + err = xenon_ac5_probe(host); + if (err) + goto err_clk_axi; + } + err = mmc_of_parse(host->mmc); if (err) goto err_clk_axi; @@ -682,6 +719,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, {} }; MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h index 3e9c6c908a79..0460d97aad26 100644 --- a/drivers/mmc/host/sdhci-xenon.h +++ b/drivers/mmc/host/sdhci-xenon.h @@ -57,7 +57,8 @@ enum xenon_variant { XENON_A3700, XENON_AP806, XENON_AP807, - XENON_CP110 + XENON_CP110, + XENON_AC5 }; struct xenon_priv {