From owner-svn-src-all@FreeBSD.ORG Sat Feb 15 20:45:54 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 2395E75C; Sat, 15 Feb 2014 20:45:54 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 013D61804; Sat, 15 Feb 2014 20:45:54 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s1FKjrgN003609; Sat, 15 Feb 2014 20:45:53 GMT (envelope-from ian@svn.freebsd.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s1FKjr8v003607; Sat, 15 Feb 2014 20:45:53 GMT (envelope-from ian@svn.freebsd.org) Message-Id: <201402152045.s1FKjr8v003607@svn.freebsd.org> From: Ian Lepore Date: Sat, 15 Feb 2014 20:45:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r261945 - head/sys/dev/sdhci X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 15 Feb 2014 20:45:54 -0000 Author: ian Date: Sat Feb 15 20:45:53 2014 New Revision: 261945 URL: http://svnweb.freebsd.org/changeset/base/261945 Log: Add timeout logic to sdhci, separate from the timeouts done by the hardware. If the hardware is not in a good state (like maybe clocks aren't running because of a configuration glitch) its timeout clock may also not work correctly, and the next command sent will hang that thread forever. The thread in question is usually the one and only thread (at init time) or a bio queue worker thread whose lockup will eventually lead to the whole system locking up when it runs out of buffers. No sd card command should take longer than 250ms. This new code establishes a 1-second timeout to allow plenty of safety margin over that. Modified: head/sys/dev/sdhci/sdhci.c head/sys/dev/sdhci/sdhci.h Modified: head/sys/dev/sdhci/sdhci.c ============================================================================== --- head/sys/dev/sdhci/sdhci.c Sat Feb 15 20:36:54 2014 (r261944) +++ head/sys/dev/sdhci/sdhci.c Sat Feb 15 20:45:53 2014 (r261945) @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -609,6 +610,7 @@ sdhci_init_slot(device_t dev, struct sdh TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); callout_init(&slot->card_callout, 1); + callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0); return (0); } @@ -623,6 +625,7 @@ sdhci_cleanup_slot(struct sdhci_slot *sl { device_t d; + callout_drain(&slot->timeout_callout); callout_drain(&slot->card_callout); taskqueue_drain(taskqueue_swi_giant, &slot->card_task); @@ -702,6 +705,32 @@ sdhci_generic_update_ios(device_t brdev, return (0); } +static void +sdhci_req_done(struct sdhci_slot *slot) +{ + struct mmc_request *req; + + if (slot->req != NULL && slot->curcmd != NULL) { + callout_stop(&slot->timeout_callout); + req = slot->req; + slot->req = NULL; + slot->curcmd = NULL; + req->done(req); + } +} + +static void +sdhci_timeout(void *arg) +{ + struct sdhci_slot *slot = arg; + + if (slot->curcmd != NULL) { + sdhci_reset(slot, SDHCI_RESET_ALL); + slot->curcmd->error = MMC_ERR_TIMEOUT; + sdhci_req_done(slot); + } +} + static void sdhci_set_transfer_mode(struct sdhci_slot *slot, struct mmc_data *data) @@ -727,7 +756,6 @@ sdhci_set_transfer_mode(struct sdhci_slo static void sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) { - struct mmc_request *req = slot->req; int flags, timeout; uint32_t mask, state; @@ -740,9 +768,7 @@ sdhci_start_command(struct sdhci_slot *s if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { slot_printf(slot, "Unsupported response type!\n"); cmd->error = MMC_ERR_FAILED; - slot->req = NULL; - slot->curcmd = NULL; - req->done(req); + sdhci_req_done(slot); return; } @@ -754,9 +780,7 @@ sdhci_start_command(struct sdhci_slot *s slot->power == 0 || slot->clock == 0) { cmd->error = MMC_ERR_FAILED; - slot->req = NULL; - slot->curcmd = NULL; - req->done(req); + sdhci_req_done(slot); return; } /* Always wait for free CMD bus. */ @@ -784,9 +808,7 @@ sdhci_start_command(struct sdhci_slot *s "inhibit bit(s).\n"); sdhci_dumpregs(slot); cmd->error = MMC_ERR_FAILED; - slot->req = NULL; - slot->curcmd = NULL; - req->done(req); + sdhci_req_done(slot); return; } timeout--; @@ -828,6 +850,8 @@ sdhci_start_command(struct sdhci_slot *s sdhci_set_transfer_mode(slot, cmd->data); /* Start command. */ WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff)); + /* Start timeout callout; no command should take more than a second. */ + callout_reset(&slot->timeout_callout, hz, sdhci_timeout, slot); } static void @@ -1013,10 +1037,7 @@ sdhci_start(struct sdhci_slot *slot) sdhci_reset(slot, SDHCI_RESET_DATA); } - /* We must be done -- bad idea to do this while locked? */ - slot->req = NULL; - slot->curcmd = NULL; - req->done(req); + sdhci_req_done(slot); } int Modified: head/sys/dev/sdhci/sdhci.h ============================================================================== --- head/sys/dev/sdhci/sdhci.h Sat Feb 15 20:36:54 2014 (r261944) +++ head/sys/dev/sdhci/sdhci.h Sat Feb 15 20:45:53 2014 (r261945) @@ -241,6 +241,7 @@ struct sdhci_slot { bus_addr_t paddr; /* DMA buffer address */ struct task card_task; /* Card presence check task */ struct callout card_callout; /* Card insert delay callout */ + struct callout timeout_callout;/* Card command/data response timeout */ struct mmc_host host; /* Host parameters */ struct mmc_request *req; /* Current request */ struct mmc_command *curcmd; /* Current command of current request */