From patchwork Sun Dec 18 20:37:58 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 5839 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id DFCC924188 for ; Sun, 18 Dec 2011 20:38:05 +0000 (UTC) Received: from mail-ey0-f180.google.com (mail-ey0-f180.google.com [209.85.215.180]) by fiordland.canonical.com (Postfix) with ESMTP id D7854A18284 for ; Sun, 18 Dec 2011 20:38:05 +0000 (UTC) Received: by mail-ey0-f180.google.com with SMTP id c11so1269910eaa.11 for ; Sun, 18 Dec 2011 12:38:05 -0800 (PST) Received: by 10.204.156.219 with SMTP id y27mr4233709bkw.125.1324240685643; Sun, 18 Dec 2011 12:38:05 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.204.40.4 with SMTP id i4cs108677bke; Sun, 18 Dec 2011 12:38:05 -0800 (PST) Received: by 10.205.122.68 with SMTP id gf4mr4436480bkc.5.1324240683133; Sun, 18 Dec 2011 12:38:03 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id ab1si6798904bkc.89.2011.12.18.12.38.02 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 18 Dec 2011 12:38:02 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1RcNUe-00070e-RN; Sun, 18 Dec 2011 20:38:00 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 08/10] hw/sd.c: Correct handling of type B SD status bits Date: Sun, 18 Dec 2011 20:37:58 +0000 Message-Id: <1324240680-26905-9-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1324240680-26905-1-git-send-email-peter.maydell@linaro.org> References: <1324240680-26905-1-git-send-email-peter.maydell@linaro.org> Correct how we handle the type B ("cleared on valid command") status bits. In particular, the CURRENT_STATE bits in a response should be the state of the card when it received that command, not the state when it received the preceding command. (This is one of the issues noted in LP:597641.) Signed-off-by: Peter Maydell --- hw/sd.c | 44 +++++++++++++++++++++++++------------------- 1 files changed, 25 insertions(+), 19 deletions(-) diff --git a/hw/sd.c b/hw/sd.c index 9eebfac..e1565b6 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -104,7 +104,7 @@ struct SDState { int enable; }; -static void sd_set_status(SDState *sd) +static void sd_set_mode(SDState *sd) { switch (sd->state) { case sd_inactive_state: @@ -126,9 +126,6 @@ static void sd_set_status(SDState *sd) sd->mode = sd_data_transfer_mode; break; } - - sd->card_status &= ~CURRENT_STATE; - sd->card_status |= sd->state << 9; } static const sd_cmd_type_t sd_cmd_type[64] = { @@ -341,13 +338,10 @@ static int sd_req_crc_validate(SDRequest *req) return sd_crc7(buffer, 5) != req->crc; /* TODO */ } -static void sd_response_r1_make(SDState *sd, - uint8_t *response, uint32_t last_status) +static void sd_response_r1_make(SDState *sd, uint8_t *response) { - uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND; - uint32_t status; - - status = (sd->card_status & ~mask) | (last_status & mask); + uint32_t status = sd->card_status; + /* Clear the "clear on read" status bits (except APP_CMD) */ sd->card_status &= ~CARD_STATUS_C | APP_CMD; response[0] = (status >> 24) & 0xff; @@ -1286,7 +1280,7 @@ static int cmd_valid_while_locked(SDState *sd, SDRequest *req) int sd_do_command(SDState *sd, SDRequest *req, uint8_t *response) { - uint32_t last_status = sd->card_status; + int last_state; sd_rsp_type_t rtype; int rsplen; @@ -1300,10 +1294,7 @@ int sd_do_command(SDState *sd, SDRequest *req, goto send_response; } - sd->card_status &= ~CARD_STATUS_B; - sd_set_status(sd); - - if (last_status & CARD_IS_LOCKED) { + if (sd->card_status & CARD_IS_LOCKED) { if (!cmd_valid_while_locked(sd, req)) { sd->card_status |= ILLEGAL_COMMAND; fprintf(stderr, "SD: Card is locked\n"); @@ -1312,7 +1303,10 @@ int sd_do_command(SDState *sd, SDRequest *req, } } - if (last_status & APP_CMD) { + last_state = sd->state; + sd_set_mode(sd); + + if (sd->card_status & APP_CMD) { rtype = sd_app_command(sd, *req); sd->card_status &= ~APP_CMD; } else @@ -1320,15 +1314,20 @@ int sd_do_command(SDState *sd, SDRequest *req, if (rtype == sd_illegal) { sd->card_status |= ILLEGAL_COMMAND; + } else { + /* Valid command, we can update the 'state before command' bits. + * (Do this now so they appear in r1 responses.) + */ + sd->current_cmd = req->cmd; + sd->card_status &= ~CURRENT_STATE; + sd->card_status |= (last_state << 9); } - sd->current_cmd = req->cmd; - send_response: switch (rtype) { case sd_r1: case sd_r1b: - sd_response_r1_make(sd, response, last_status); + sd_response_r1_make(sd, response); rsplen = 4; break; @@ -1364,6 +1363,13 @@ send_response: break; } + if (rtype != sd_illegal) { + /* Clear the "clear on valid command" status bits now we've + * sent any response + */ + sd->card_status &= ~CARD_STATUS_B; + } + #ifdef DEBUG_SD if (rsplen) { int i;