From patchwork Mon Feb 1 22:15:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Baumann X-Patchwork-Id: 8184091 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 09DD79F1C1 for ; Mon, 1 Feb 2016 22:16:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DC43720392 for ; Mon, 1 Feb 2016 22:16:15 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8E70F2035E for ; Mon, 1 Feb 2016 22:16:14 +0000 (UTC) Received: from localhost ([::1]:54255 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQMlZ-0000Mc-K4 for patchwork-qemu-devel@patchwork.kernel.org; Mon, 01 Feb 2016 17:16:13 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60611) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQMlJ-0000Lo-3p for qemu-devel@nongnu.org; Mon, 01 Feb 2016 17:15:58 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aQMlG-0002pV-Jq for qemu-devel@nongnu.org; Mon, 01 Feb 2016 17:15:57 -0500 Received: from mail-bn1bn0102.outbound.protection.outlook.com ([157.56.110.102]:62736 helo=na01-bn1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQMlG-0002ob-CR for qemu-devel@nongnu.org; Mon, 01 Feb 2016 17:15:54 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:To:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=fahtaOBh7K5lEHXfdYS5LsL2VWJ2ZZE+R2zcTmdE39g=; b=aKpvl4mOMpBeXFwFG+u29nvsLZEEClEuO+/WAqC8blKzYvpPjs7E9G9rIKfl9dfrhyVPdFPZH7Y5PXuqom32pP6MhlPMK4dAN35BNnUyFupynlRxQZclS3MHHU7XvFfkDzx6GTA9lkN+R5IFj4X2BT/TASCnwWh2UCeO3KrbI5U= Authentication-Results: nongnu.org; dkim=none (message not signed) header.d=none; nongnu.org; dmarc=none action=none header.from=microsoft.com; Received: from baumann-desk.redmond.corp.microsoft.com (2001:4898:80e8:4::724) by CY1PR0301MB2041.namprd03.prod.outlook.com (10.164.2.23) with Microsoft SMTP Server (TLS) id 15.1.396.15; Mon, 1 Feb 2016 22:15:52 +0000 From: Andrew Baumann To: Date: Mon, 1 Feb 2016 14:15:35 -0800 Message-ID: <1454364936-18940-3-git-send-email-Andrew.Baumann@microsoft.com> X-Mailer: git-send-email 2.5.1 In-Reply-To: <1454364936-18940-1-git-send-email-Andrew.Baumann@microsoft.com> References: <1454364936-18940-1-git-send-email-Andrew.Baumann@microsoft.com> MIME-Version: 1.0 X-Originating-IP: [2001:4898:80e8:4::724] X-ClientProxiedBy: CO1PR06CA059.namprd06.prod.outlook.com (10.242.160.49) To CY1PR0301MB2041.namprd03.prod.outlook.com (25.164.2.23) X-MS-Office365-Filtering-Correlation-Id: a71c3e05-2e12-41ea-2040-08d32b553f97 X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB2041; 2:fdGLzMQnh1rttYeVIMBxrisnGLcMqxm0WFN9sRR3WAUnsG8wBjQZrW79GV7zshkIncAtTf4ggmNRNfz747OiqDuNbSqML+NYagSVWmLhECmA4k3+jWXzghWrL2VvE425FgYp8I+oIueXwJ8Fn5xlsMa8m8p5TFCSS6C6On5DUwiohsnjuRhLO+plesFXam2X; 3:YoCWN8fshjfIYtwomxzrvT5mUniBrt+bnso26zOhBsOOvrQBq+NQfsVzMyq73HjGFLD+EyTLG+B3CqbtJYcXzboOFWIsMQXyFUmEfQinSCqyMh9zZHdvm/30fBqf/7oG; 25:y5FDH38cqXoHtzVmzo/cJsLUUhIJ9EItpfjoxEFev4T3Hubt4R4fMbsIIz0fjnHx92Y/BejYaysjDqUjBCNpZ6EGdtW0XoRjwCl5tZ1TjkXsqiAMVsbvIUQtbfEufAAWrXRJMfzvvPisYtFoeYEF5DR66MGqZ8fYWMowJ/hbJb+djyWfejbbck9o2hobAFS6eGdEMtitYVMRYEoQjNMAr8MVAcJqiukLHvLJ+q6PZxNkxIUD1zkVjWBkZKvQl+5s2X97VHu9EVPZHLdTCU7E3PiZ+q+ypqcP4Zahwm8uFwE= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR0301MB2041; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB2041; 20:+1i9VhcYBNU5kWPHMhqhkTymi4ESrgn1zOkxM8HsvUoLC6niL5OD9x6PPbzdg+4I4qbIjxsReqbZkhW4BYP3e3y6GBgKVWzDj2RQ6Wtg/7xEeMe0jBYKvoMxNOh4vTvhtt42eN9thZACcClh0ESG1NzyDjR7KSsY8SNXRYgtQSSj+3ALmWGaDwlZ5R7ZHVhbHIpORIzbiYu87ddWvB9/wvQyM/n5ufkPTtpDZ38ItVMiSgLaS2QzIBBaQ2PZzvwmb7nzRaw79zcr2pjFo5n1ylKyacaOo7EAX+XbbkKz4oRcS9VfCAj5SdZfoc4IqU7Cxerv1nDI//sbq5VcrXM1RelVbnjzz2te/RTnJ4tO01JuLhyyvOZY8lgCYTt/SVEPgbSv16Z3rbCnTcg8ODyvbj4ii0R+hb47dm4RIJsF+rHsEqGPTfnlqbv2tY4GW9hquO1MMXxZA3zgLYEvd6dCb77Y8PB4YX36kULxq7dczS7gFPTHJa5gUWlYBvy7g0Np; 4:3iqUZPmfq+YENSv7TQB8pl5tRHz+L4whGLT8YGX1/deYLQUmhgWXYgRV6RwsiKe6Fvnde754s1AopaJn1BEBMJaVQ6USRvJUGR326HtxSc8AH4pgBz52dlYZIahywvpqdkBkIx/ThHTz+ZzPGzyS6Q9pbMXNiIM524pk81tw3gKiUwHFAHlnx3ARx1bVf7jZpaCjuc6mH1CqYp7gfx27O0EeT5hXcG3dMDRdyWBVjhy95VCn8B/eyqj1scia+4mdb3YPFpvwmAMZAixSOQXvxEKY9n+RInAu2SAXK9KNFq/cIUrouZB+zRD4PM0Inl7YzW2JsDSPORSk05NzeTEJ8y5YOG705zYEoW9ONCYvjM8/f+X+A9H140U3yIa7HeWk X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046); SRVR:CY1PR0301MB2041; BCL:0; PCL:0; RULEID:; SRVR:CY1PR0301MB2041; X-Forefront-PRVS: 0839D067E7 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(36756003)(122386002)(77096005)(6116002)(50466002)(40100003)(10290500002)(4001430100002)(50986999)(92566002)(5004730100002)(15975445007)(5008740100001)(107886002)(87976001)(2950100001)(5005710100001)(110136002)(5001960100002)(1096002)(76176999)(586003)(2906002)(3470700001)(4326007)(189998001)(2351001)(42186005)(47776003)(86362001)(19580395003)(19580405001)(50226001)(48376002)(5003940100001)(86612001)(229853001)(10090500001)(7059030)(3826002); DIR:OUT; SFP:1102; SCL:1; SRVR:CY1PR0301MB2041; H:baumann-desk.redmond.corp.microsoft.com; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR0301MB2041; 23:YIkRKoV2Qy5zxGc7rNXCxbZROlkgzykq0wHQEkw?= =?us-ascii?Q?tY8xJoq3Ab4ecnDVNQ0W+sIcUOTsnVoIeatAjfaQO/N+lbFDvSNMSWrYEMRB?= =?us-ascii?Q?I5RZLeg6A1zVI0IHr6IGIyWS2Xqlg1pEN6x3L1T91oIrYlKJSnYwa4YYrS3e?= =?us-ascii?Q?4c5nhPsN3H0DWlC0CvU0whdecTlo6N7pyAZQVnpFDJaDEFOz1QmMM2NcCzoL?= =?us-ascii?Q?DTV6h7GRDxkV6iElfF2PEQoCMtjfsQ3R+nO9REjTjHFlzpI87MBFFhcDSmv1?= =?us-ascii?Q?kwYWs44yWhPrLQvYfzocm7DtOsQQgfzG0tjA5i3T9Uhy36YOiz0R8XG0H1AG?= =?us-ascii?Q?awiNt/W9sJtuvj9GDWGHjYOe42yF+Xh3uskvqnar/ldY7avruBiYB+nlmBRj?= =?us-ascii?Q?Yi6orSCwAzx1ppeh5nABzzh22YbE3560ktQ+DR1RTMC+X+jt98Ie3TqpuwZB?= =?us-ascii?Q?qmgpkrV7GxLA27pM5KZJy4gt9Zp0v/y/C2YGydLsEviXwwS3iyyPOXxJyO4u?= =?us-ascii?Q?1jVKKz1DO/a3mdvaPSxxUxtnD9lUJUX5McP4JiSB46YmRSyf1yuFnzzH9QtC?= =?us-ascii?Q?GKvRPe0z8nyvj8mQhw1dLFVOsIetgFu97y2FkeeET1liGj2djt+C1sdex4kk?= =?us-ascii?Q?Gb8Y7o1BmLhoBKmlB84KxfPBAOBz8JxsZLn8Np+T3gfz1WOEiwRpG5NfJxVR?= =?us-ascii?Q?hl+ppxii3CHbBkprrpDtoP9EoN313142Ah6KdMhk9YRqjmZv7ouhfFeBRdq8?= =?us-ascii?Q?H1dPehBGAFPs4f5jZ7cVvkTszxf1Vz4X+KRLHgrbJ//ywhtenq0sHFfnZNY2?= =?us-ascii?Q?C6t2a3nNYoQmp3AzYdqzzZwS/rNZgHVScQeNaMqcHIjWDFsibdotOXic3UbX?= =?us-ascii?Q?p2kNeDnDa88DKe1Bq0cJQCINSwJ7MI+BG4YpYOnMyc1zSzYStX4HYLJ7CV9W?= =?us-ascii?Q?0oFGAYtsK3Y955eXNAUjPlPyp2AbVDuRYljVJ2sWskPlfsJvhfwEm61okejz?= =?us-ascii?Q?tbwNYsBxEqFdiSskzkAiu4W1J2KupCA05Mod08eobVny45g5QGiYE+nKHR1c?= =?us-ascii?Q?SW7k1JShA2zCSIc0N8vcdVYyf8qwzGxohb88iHS4Z+SMz9K3f29OdY83rAyd?= =?us-ascii?Q?9Tqv19lMcXfw=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB2041; 5:zRZqQtQW+OUmNTvm3ajbx5cSdQRNkIxDC06DnyuYyymx0zCZWGwx1SRCufeSmKGaXBajOTasFuSIS4fQlWTtYAaKSr+GYIXujpQ+CzyRjH5+6djevsIA69TLUtALHMGXMQoEse/KAy6X/siW+ygOrg==; 24:oSMgHwka8BsSrlZUuvFval2IbqBPqj2CDjPcoV8xoMdthKSe1tnplvxNkSbXSAlC6nQv12lrc1Qh5uLgFPQvQ45qW7YLKrEDz5Kw5ZaRVPM= X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Feb 2016 22:15:52.5432 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR0301MB2041 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 X-Received-From: 157.56.110.102 Cc: Peter Maydell , Juan Quintela , Igor Mitsyanko , Andrew Baumann , Sai Pavan Boddu , Peter Crosthwaite , Stefan Hajnoczi Subject: [Qemu-devel] [PATCH v3 2/3] hw/sd: model a power-up delay, as a workaround for an EDK2 bug X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The SD spec for ACMD41 says that a zero argument is an "inquiry" ACMD41, which does not start initialisation and is used only for retrieving the OCR. However, Tianocore EDK2 (UEFI) has a bug [1]: it first sends an inquiry (zero) ACMD41. If that first request returns an OCR value with the power up bit (0x80000000) set, it assumes the card is ready and continues, leaving the card in the wrong state. (My assumption is that this works on hardware, because no real card is immediately powered up upon reset.) This change models a delay of 0.5ms from the first ACMD41 to the power being up. However, it also immediately sets the power on upon seeing a non-zero (non-enquiry) ACMD41. This speeds up UEFI boot, it should also account for guests that simply delay after card reset and then issue an ACMD41 that they expect will succeed. [1] https://github.com/tianocore/edk2/blob/master/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c#L279 (This is the loop starting with "We need to wait for the MMC or SD card is ready") Signed-off-by: Andrew Baumann Reviewed-by: Peter Maydell --- Obviously this is a bug that should be fixed in EDK2. However, this initialisation appears to have been around for quite a while in EDK2 (in various forms), and the fact that it has obviously worked with so many real SD/MMC cards makes me think that it would be pragmatic to have the workaround in QEMU as well. You might argue that the delay timer should start on sd_reset(), and not the first ACMD41. However, that doesn't work reliably with UEFI, because a large delay often elapses between the two (particularly in debug builds that do lots of printing to the serial port). If the timer fires too early, we'll still hit the bug, but we also don't want to set a huge timeout value, because some guests may depend on it expiring. hw/sd/sd.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 6 deletions(-) mode change 100644 => 100755 hw/sd/sd.c diff --git a/hw/sd/sd.c b/hw/sd/sd.c old mode 100644 new mode 100755 index 8514ac7..473d4a0 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -36,6 +36,7 @@ #include "qemu/bitmap.h" #include "hw/qdev-properties.h" #include "qemu/error-report.h" +#include "qemu/timer.h" //#define DEBUG_SD 1 @@ -46,7 +47,9 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif -#define ACMD41_ENQUIRY_MASK 0x00ffffff +#define ACMD41_ENQUIRY_MASK 0x00ffffff +#define OCR_POWER_UP 0x80000000 +#define OCR_POWER_DELAY (get_ticks_per_sec() / 2000) /* 0.5ms */ typedef enum { sd_r0 = 0, /* no response */ @@ -85,6 +88,7 @@ struct SDState { uint32_t mode; /* current card mode, one of SDCardModes */ int32_t state; /* current card state, one of SDCardStates */ uint32_t ocr; + QEMUTimer *ocr_power_timer; uint8_t scr[8]; uint8_t cid[16]; uint8_t csd[16]; @@ -199,8 +203,17 @@ static uint16_t sd_crc16(void *message, size_t width) static void sd_set_ocr(SDState *sd) { - /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */ - sd->ocr = 0x80ffff00; + /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */ + sd->ocr = 0x00ffff00; +} + +static void sd_ocr_powerup(void *opaque) +{ + SDState *sd = opaque; + + /* Set powered up bit in OCR */ + assert(!(sd->ocr & OCR_POWER_UP)); + sd->ocr |= OCR_POWER_UP; } static void sd_set_scr(SDState *sd) @@ -475,10 +488,44 @@ static const BlockDevOps sd_block_ops = { .change_media_cb = sd_cardchange, }; +static bool sd_ocr_vmstate_needed(void *opaque) +{ + SDState *sd = opaque; + + /* Include the OCR state (and timer) if it is not yet powered up */ + return !(sd->ocr & OCR_POWER_UP); +} + +static const VMStateDescription sd_ocr_vmstate = { + .name = "sd-card/ocr-state", + .version_id = 1, + .minimum_version_id = 1, + .needed = sd_ocr_vmstate_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ocr, SDState), + VMSTATE_TIMER_PTR(ocr_power_timer, SDState), + VMSTATE_END_OF_LIST() + }, +}; + +static int sd_vmstate_pre_load(void *opaque) +{ + SDState *sd = opaque; + + /* If the OCR state is not included (prior versions, or not + * needed), then the OCR must be set as powered up. If the OCR state + * is included, this will be replaced by the state restore. + */ + sd_ocr_powerup(sd); + + return 0; +} + static const VMStateDescription sd_vmstate = { .name = "sd-card", .version_id = 1, .minimum_version_id = 1, + .pre_load = sd_vmstate_pre_load, .fields = (VMStateField[]) { VMSTATE_UINT32(mode, SDState), VMSTATE_INT32(state, SDState), @@ -505,7 +552,11 @@ static const VMStateDescription sd_vmstate = { VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512), VMSTATE_BOOL(enable, SDState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription*[]) { + &sd_ocr_vmstate, + NULL + }, }; /* Legacy initialization function for use by non-qdevified callers */ @@ -1320,12 +1371,31 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (sd->state) { case sd_idle_state: + /* If it's the first ACMD41 since reset, we need to decide + * whether to power up. If this is not an enquiry ACMD41, + * we immediately report power on and proceed below to the + * ready state, but if it is, we set a timer to model a + * delay for power up. This works around a bug in EDK2 + * UEFI, which sends an initial enquiry ACMD41, but + * assumes that the card is in ready state as soon as it + * sees the power up bit set. */ + if (!(sd->ocr & OCR_POWER_UP)) { + if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { + timer_del(sd->ocr_power_timer); + sd_ocr_powerup(sd); + } else if (!timer_pending(sd->ocr_power_timer)) { + timer_mod(sd->ocr_power_timer, + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + OCR_POWER_DELAY)); + } + } + /* We accept any voltage. 10000 V is nothing. * - * We don't model init delay so just advance straight to ready state + * Once we're powered up, we advance straight to ready state * unless it's an enquiry ACMD41 (bits 23:0 == 0). */ - if (req.arg & ACMD41_ENQUIRY_MASK) { + if ((sd->ocr & OCR_POWER_UP) && (req.arg & ACMD41_ENQUIRY_MASK)) { sd->state = sd_ready_state; } @@ -1833,6 +1903,7 @@ static void sd_instance_init(Object *obj) SDState *sd = SD_CARD(obj); sd->enable = true; + sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd); } static void sd_realize(DeviceState *dev, Error **errp)