From patchwork Mon Mar 19 16:15:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 132059 Delivered-To: patches@linaro.org Received: by 10.80.152.129 with SMTP id j1csp2998340edb; Mon, 19 Mar 2018 09:16:01 -0700 (PDT) X-Google-Smtp-Source: AG47ELsIg5HirvFpZ5y0n1f67kbGMksVhVyJ+NENeqhiigEdSGg71+K1nNwjRe5UrYSWpdWNZC1J X-Received: by 10.46.152.143 with SMTP id b15mr8019910ljj.131.1521476161167; Mon, 19 Mar 2018 09:16:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521476161; cv=none; d=google.com; s=arc-20160816; b=hx+T/If8TGBj38emVA6jOIfCIYUynsEFrl0nhRUejLuLMNAwwZRwOrfp2f84iwi94v Qun3dufFNfVsZZvxibGYaBhpo+2IqWQFnWn5xB0wR2kEvLzTAq7M3JrLM7cDjoQnGSys x2pzTo6QWp71o7co83fAyX9vE8UZtGQZ21L90+gdeCzIogkc/PnGYFK3vw8uyqDobbT0 TAgwBCOpy0kWKG6o85zAdpe9t8in2sMPr203OIc/gupOc0t8ANqRRkPjiqk6j/UmUpDh CDfKD9KfawztzjCGhkAOCEgqeSpALZRuT/tPEGORxpcEqj56ZanZuJCNvT0HzU3SaxfO 8dFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=8Mi6sQA6C13VH2Kf79kMVqQA5tAkjPYSboAliBWWx64=; b=QX6TPEtYSpe7DIm6kal6eMAVJm+ckAV1gC1T+ZLaL7ETmcGLfiRnhd0/9csECGdTx3 9HQmoLzztS4y4O0EZ0cf4/2rT9qEx4ggV4YNvoVBpa2QDmycYWiGI7eWAgEXQkYNsPMa OY5RtsTMh9ZJVxASduOM3kFQlxvLIITesz7kTpNoDPiEUBygQ+Fc4qG8HlFjj+xTGDNn UmK955gVeg0US2/iapL8mBJp0q40lElRtELAo92GtAnXD8SK2l9U1ZwJm504BxH9XoOa +F8q3xYReKzaZ5vt4il7bOgAx0g69hqKRnqFnBB5gvgj+0C7j1YSIztG5vl12zjnoktS 9iaQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id p9si92113ljg.479.2018.03.19.09.16.00 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 19 Mar 2018 09:16:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1exxS3-0002tj-Lr; Mon, 19 Mar 2018 16:15:59 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Gerd Hoffmann , =?utf-8?q?Philippe_Mathieu-Daud?= =?utf-8?b?w6k=?= , Pekka Enberg , Andrew Baumann Subject: [PATCH for-2.12 2/2] hw/sd/bcm2835_sdhost: Don't raise spurious interrupts Date: Mon, 19 Mar 2018 16:15:56 +0000 Message-Id: <20180319161556.16446-3-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180319161556.16446-1-peter.maydell@linaro.org> References: <20180319161556.16446-1-peter.maydell@linaro.org> The Linux bcm2835_sdhost driver doesn't work on QEMU, because our model raises spurious data interrupts. Our function bcm2835_sdhost_fifo_run() will flag an interrupt any time it is called with s->datacnt == 0, even if the host hasn't actually issued a data read or write command yet. This means that the driver gets a spurious data interrupt as soon as it enables IRQs and then does something else that causes us to call the fifo_run routine, like writing to SDHCFG, and before it does the write to SDCMD to issue the read. The driver's IRQ handler then spins forever complaining that there's no data and the SD controller isn't in a state where there's going to be any data: [ 41.040738] sdhost-bcm2835 3f202000.mmc: fsm 1, hsts 00000000 [ 41.042059] sdhost-bcm2835 3f202000.mmc: fsm 1, hsts 00000000 (continues forever). Move the interrupt flag setting to more plausible places: * for BUSY, raise this as soon as a BUSYWAIT command has executed * for DATA, raise this when the FIFO has any space free (for a write) or any data in it (for a read) * for BLOCK, raise this when the data count is 0 and we've actually done some reading or writing This is pure guesswork since the documentation for this hardware is not public, but it is sufficient to get the Linux bcm2835_sdhost driver to work. Signed-off-by: Peter Maydell --- hw/sd/bcm2835_sdhost.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) -- 2.16.2 Reviewed-by: Philippe Mathieu-Daudé diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c index 79f3c5ceeb..0fd0853fa3 100644 --- a/hw/sd/bcm2835_sdhost.c +++ b/hw/sd/bcm2835_sdhost.c @@ -137,6 +137,9 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s) } #undef RWORD } + if ((s->cmd & SDCMD_BUSYWAIT) && (s->config & SDHCFG_BUSY_IRPT_EN)) { + s->status |= SDHSTS_BUSY_IRPT; + } return; error: @@ -187,18 +190,27 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) n++; if (n == 4) { bcm2835_sdhost_fifo_push(s, value); + s->status |= SDHSTS_DATA_FLAG; + if (s->config & SDHCFG_DATA_IRPT_EN) { + s->status |= SDHSTS_SDIO_IRPT; + } n = 0; value = 0; } } if (n != 0) { bcm2835_sdhost_fifo_push(s, value); + s->status |= SDHSTS_DATA_FLAG; } } else { /* write */ n = 0; while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { if (n == 0) { value = bcm2835_sdhost_fifo_pop(s); + s->status |= SDHSTS_DATA_FLAG; + if (s->config & SDHCFG_DATA_IRPT_EN) { + s->status |= SDHSTS_SDIO_IRPT; + } n = 4; } n--; @@ -207,28 +219,19 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) value >>= 8; } } + if (s->datacnt == 0) { + s->edm &= ~0xf; + s->edm |= SDEDM_FSM_DATAMODE; + trace_bcm2835_sdhost_edm_change("datacnt 0", s->edm); + + if ((s->cmd & SDCMD_WRITE_CMD) && + (s->config & SDHCFG_BLOCK_IRPT_EN)) { + s->status |= SDHSTS_BLOCK_IRPT; + } + } } - if (s->datacnt == 0) { - s->status |= SDHSTS_DATA_FLAG; - s->edm &= ~0xf; - s->edm |= SDEDM_FSM_DATAMODE; - trace_bcm2835_sdhost_edm_change("datacnt 0", s->edm); - - if (s->config & SDHCFG_DATA_IRPT_EN) { - s->status |= SDHSTS_SDIO_IRPT; - } - - if ((s->cmd & SDCMD_BUSYWAIT) && (s->config & SDHCFG_BUSY_IRPT_EN)) { - s->status |= SDHSTS_BUSY_IRPT; - } - - if ((s->cmd & SDCMD_WRITE_CMD) && (s->config & SDHCFG_BLOCK_IRPT_EN)) { - s->status |= SDHSTS_BLOCK_IRPT; - } - - bcm2835_sdhost_update_irq(s); - } + bcm2835_sdhost_update_irq(s); s->edm &= ~(0x1f << 4); s->edm |= ((s->fifo_len & 0x1f) << 4);