@@ -202,11 +202,14 @@ static void mmc_wait_done(struct mmc_request *mrq)
* @host: MMC host to start command
* @mrq: MMC request to start
*
- * Start a new MMC custom command request for a host, and wait
- * for the command to complete. Does not attempt to parse the
- * response.
+ * Implementation hander for starting a new MMC custom command request
+ * for a host, and wait for the command to complete. Does not attempt to
+ * parse the response.
+ *
+ * We provide this separately and export it so that it can be wrapped
+ * by callers who need serialization or have other issue constraints
*/
-void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+void mmc_do_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
DECLARE_COMPLETION_ONSTACK(complete);
@@ -218,6 +221,25 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
wait_for_completion(&complete);
}
+EXPORT_SYMBOL(mmc_do_wait_for_req);
+
+/**
+ * mmc_wait_for_req - start a request and wait for completion
+ * @host: MMC host to start command
+ * @mrq: MMC request to start
+ *
+ * Start a new MMC custom command request for a host, and wait
+ * for the command to complete. Does not attempt to parse the
+ * response.
+ */
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (host->ops->wait_for_req)
+ host->ops->wait_for_req(host, mrq);
+ else
+ return mmc_do_wait_for_req(host, mrq);
+}
+
EXPORT_SYMBOL(mmc_wait_for_req);
/**
@@ -18,20 +18,27 @@
* that keeps them out of the main flow. We can't just make it a new
* driver as the shdci core code isn't really a library.
*/
-
+
+/*
+ * Support serialization
+ */
+
+static DEFINE_MUTEX(port_mutex);
+
+static void sdhci_intel_wait_req(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ mutex_lock(&port_mutex);
+ mmc_do_wait_for_req(host->mmc, mrq);
+ mutex_unlock(&port_mutex);
+}
+
+/*
+ * Handle the Moorestown reset
+ */
static void sdhci_broken_reset(struct sdhci_host *host, u8 mask)
{
unsigned long timeout;
- u32 uninitialized_var(ier);
-
- if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT))
- return;
- }
-
- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
@@ -46,12 +53,11 @@ static void sdhci_broken_reset(struct sdhci_host *host, u8 mask)
if (timeout == 0) {
printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
+ return;
}
timeout--;
mdelay(1);
}
- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
}
static void sdhci_mid_broken_resetall(struct sdhci_host *host, int down)
@@ -156,6 +162,7 @@ struct sdhci_ops sdhci_intel_mrst_hc = {
.set_ios = sdhci_lnw_a3_set_ios,
.reset_all = sdhci_mid_broken_resetall,
.write_command = sdhci_clockreset_wcmd,
+ .wait_for_req = sdhci_intel_wait_req,
.unexpected_cmd_irq = sdhci_lnw_a3_unexpected_cmd,
};
EXPORT_SYMBOL_GPL(sdhci_intel_mrst_hc);
@@ -55,6 +55,8 @@ struct sdhci_pci_fixes {
pm_message_t);
int (*resume)(struct sdhci_pci_chip*);
+ /* Allow the driver to override some operations for particularly
+ quirky chips */
struct sdhci_ops *host_ops;
};
@@ -1268,6 +1268,12 @@ out:
spin_unlock_irqrestore(&host->lock, flags);
}
+static void sdhci_wait_for_req(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ host->ops->wait_for_req(host, mrq);
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
@@ -1275,6 +1281,16 @@ static const struct mmc_host_ops sdhci_ops = {
.enable_sdio_irq = sdhci_enable_sdio_irq,
};
+/* Operations struct we use if the controller has an sdhci level
+ ops->wait_for_req */
+static const struct mmc_host_ops sdhci_ops_wait = {
+ .request = sdhci_request,
+ .set_ios = sdhci_set_ios,
+ .get_ro = sdhci_get_ro,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
+ .wait_for_req = sdhci_wait_for_req,
+};
+
/*****************************************************************************\
* *
* Tasklets *
@@ -1839,6 +1855,8 @@ int sdhci_add_host(struct sdhci_host *host)
* Set host parameters.
*/
mmc->ops = &sdhci_ops;
+ if (host->ops->wait_for_req)
+ mmc->ops = &sdhci_ops_wait;
if (host->ops->get_min_clock)
mmc->f_min = host->ops->get_min_clock(host);
else
@@ -334,6 +334,7 @@ struct sdhci_ops {
struct mmc_ios *ios, u8 ctrl);
void (*set_caps)(struct sdhci_host *host);
void (*unexpected_cmd_irq)(struct sdhci_host *host, u32 intmask);
+ void (*wait_for_req)(struct sdhci_host *host, struct mmc_request *mrq);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -132,6 +132,7 @@ struct mmc_host;
struct mmc_card;
extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+extern void mmc_do_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
@@ -111,6 +111,9 @@ struct mmc_host_ops {
/* optional callback for HC quirks */
void (*init_card)(struct mmc_host *host, struct mmc_card *card);
+ /* optional callback for serialization */
+ void (*wait_for_req)(struct mmc_host *host,
+ struct mmc_request *mrq);
};
struct mmc_card;