--- zzzz-none-000/linux-2.6.39.4/drivers/mmc/core/core.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-arm-6490-729/linux-2.6.39.4/drivers/mmc/core/core.c 2021-11-10 13:23:10.000000000 +0000 @@ -10,6 +10,13 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + + /****************************************************************** + + + + Includes Intel Corporation's changes/modifications dated: 07/2012. + + Changed/modified portions - Copyright(c) 2012, Intel Corporation. + + + +******************************************************************/ #include #include #include @@ -37,9 +44,26 @@ #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" - +#if defined(CONFIG_HW_MUTEXES) +#if defined(CONFIG_ARCH_GEN3) +#include +#include +#if defined(CONFIG_CE_MAILBOX) +#include +#endif // CONFIG_CE_MAILBOX +#else // -> CONFIG_ARCH_GEN3_MMC +#include +#include +#endif // CONFIG_ARCH_GEN3 +#include +#endif // CONFIG_HW_MUTEXES static struct workqueue_struct *workqueue; +#ifdef CONFIG_ARCH_GEN3 +extern int scan_thread_done; +extern int intelce_boot_mode; +#endif + /* * Enabling software CRCs on the data blocks can be a significant (30%) * performance cost, and for other reasons may not always be desired. @@ -48,6 +72,15 @@ int use_spi_crc = 1; module_param(use_spi_crc, bool, 0); +/* Enable Debug flag */ +int mmc_core_debug = 0; + +#ifdef pr_debug +#undef pr_debug +#endif + +#define pr_debug(fmt, ...) if (mmc_core_debug) printk(fmt, ##__VA_ARGS__) + /* * We normally treat cards as removed during suspend if they are not * known to be on a non-removable bus, to avoid the risk of writing @@ -101,7 +134,7 @@ } if (err && cmd->retries) { - pr_debug("%s: req failed (CMD%u): %d, retrying...\n", + pr_debug("%s: req failed (CMD%u): err=%d, retrying...\n", mmc_hostname(host), cmd->opcode, err); cmd->retries--; @@ -110,19 +143,19 @@ } else { led_trigger_event(host->led, LED_OFF); - pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", + pr_debug("%s: req done (CMD%u): err=%d, rsp[%08x %08x %08x %08x]\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (mrq->data) { - pr_debug("%s: %d bytes transferred: %d\n", + pr_debug("%s: %d bytes transferred: data error=%d\n", mmc_hostname(host), mrq->data->bytes_xfered, mrq->data->error); } if (mrq->stop) { - pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n", + pr_debug("%s: (CMD%u): err=%d, rsp[%08x %08x %08x %08x]\n", mmc_hostname(host), mrq->stop->opcode, mrq->stop->error, mrq->stop->resp[0], mrq->stop->resp[1], @@ -497,6 +530,18 @@ wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); +#if (defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC)) && defined(CONFIG_HW_MUTEXES) + spin_lock_irqsave(&host->lock, flags); + /* + * mmc_claim_host is the start point of a set of MMC operations. + * Lock HW Mutex at the first time when a task owned the controller. + */ + if ((host->claimer == current) && (host->claim_cnt == 1)) { + spin_unlock_irqrestore(&host->lock, flags); + LOCK_EMMC_HW_MUTEX(host); + } else + spin_unlock_irqrestore(&host->lock, flags); +#endif if (!stop) mmc_host_enable(host); return stop; @@ -504,6 +549,47 @@ EXPORT_SYMBOL(__mmc_claim_host); +#if defined(CONFIG_ARCH_GEN3) +/** + * __mmc_claim_host - exclusively claim a host without taking hw mutex + */ +int __mmc_claim_host_no_hwmutex(struct mmc_host *host, atomic_t *abort) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int stop; + + might_sleep(); + + add_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + while (1) { + set_current_state(TASK_UNINTERRUPTIBLE); + stop = abort ? atomic_read(abort) : 0; + if (stop || !host->claimed || host->claimer == current) + break; + spin_unlock_irqrestore(&host->lock, flags); + schedule(); + spin_lock_irqsave(&host->lock, flags); + } + set_current_state(TASK_RUNNING); + if (!stop) { + host->claimed = 1; + host->claimer = current; + host->claim_cnt += 1; + } else + wake_up(&host->wq); + spin_unlock_irqrestore(&host->lock, flags); + remove_wait_queue(&host->wq, &wait); + if (!stop) + mmc_host_enable(host); + return stop; +} +EXPORT_SYMBOL(__mmc_claim_host_no_hwmutex); +#endif + + + /** * mmc_try_claim_host - try exclusively to claim a host * @host: mmc host to claim @@ -523,6 +609,16 @@ claimed_host = 1; } spin_unlock_irqrestore(&host->lock, flags); +#if (defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC)) && defined(CONFIG_HW_MUTEXES) + spin_lock_irqsave(&host->lock, flags); + /* Lock HW Mutex at the first time when a task owned the controller. */ + if ((host->claimer == current) && (host->claim_cnt == 1)) { + spin_unlock_irqrestore(&host->lock, flags); + LOCK_EMMC_HW_MUTEX(host); + } else + spin_unlock_irqrestore(&host->lock, flags); +#endif + return claimed_host; } EXPORT_SYMBOL(mmc_try_claim_host); @@ -546,11 +642,42 @@ host->claimed = 0; host->claimer = NULL; spin_unlock_irqrestore(&host->lock, flags); +#if (defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC))&& defined(CONFIG_HW_MUTEXES) + /* + * mmc_release_host is the end point of a set of MMC operations. + * Unlock the HW Mutex when a task doesn't own the controller + */ + UNLOCK_EMMC_HW_MUTEX(host); +#endif wake_up(&host->wq); } } EXPORT_SYMBOL(mmc_do_release_host); +#if defined(CONFIG_ARCH_GEN3) +/** + * mmc_do_release_host - release a claimed host without release hw mutex + */ +void mmc_do_release_host_no_hwmutex(struct mmc_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (--host->claim_cnt) { + /* Release for nested claim */ + spin_unlock_irqrestore(&host->lock, flags); + } else { + host->claimed = 0; + host->claimer = NULL; + spin_unlock_irqrestore(&host->lock, flags); + wake_up(&host->wq); + } +} +EXPORT_SYMBOL(mmc_do_release_host_no_hwmutex); +#endif + + + void mmc_host_deeper_disable(struct work_struct *work) { struct mmc_host *host = @@ -612,6 +739,23 @@ EXPORT_SYMBOL(mmc_release_host); +#if defined(CONFIG_ARCH_GEN3) +/** + * mmc_release_host - release a host without release hw mutex + */ +void mmc_release_host_no_hwmutex(struct mmc_host *host) +{ + WARN_ON(!host->claimed); + + mmc_host_lazy_disable(host); + + mmc_do_release_host_no_hwmutex(host); +} + +EXPORT_SYMBOL(mmc_release_host_no_hwmutex); +#endif + + /* * Internal function that does the actual ios call to the host driver, * optionally printing some debug output. @@ -985,6 +1129,9 @@ host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + host->ios.ddr = MMC_SDR_MODE; +#endif mmc_set_ios(host); /* @@ -1023,6 +1170,9 @@ host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + host->ios.ddr = MMC_SDR_MODE; +#endif mmc_set_ios(host); } @@ -1532,11 +1682,15 @@ return -EIO; } +extern void sync_printk(void); void mmc_rescan(struct work_struct *work) { static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; struct mmc_host *host = container_of(work, struct mmc_host, detect.work); +#if defined(CONFIG_ARCH_GEN3) && defined(CONFIG_HW_MUTEXES) + struct sdhci_host *shost = (struct sdhci_host *)host->private; +#endif int i; if (host->rescan_disable) @@ -1574,16 +1728,68 @@ if (host->ops->get_cd && host->ops->get_cd(host) == 0) goto out; +#if defined(CONFIG_ARCH_GEN3) + if (intelce_boot_mode == 1) { + mmc_claim_host_no_hwmutex(host); + } else { + mmc_claim_host(host); + } +#else mmc_claim_host(host); +#endif + for (i = 0; i < ARRAY_SIZE(freqs); i++) { if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) break; if (freqs[i] < host->f_min) break; } + +#if defined(CONFIG_ARCH_GEN3) + if (intelce_boot_mode == 1) { + mmc_release_host_no_hwmutex(host); + } else { + mmc_release_host(host); + } +#else mmc_release_host(host); +#endif - out: +#if defined(CONFIG_HW_MUTEXES) +#if defined(CONFIG_ARCH_GEN3) && defined(CONFIG_CE_MAILBOX) + if (sdhci_host_has_HWMTX(shost) && (intelce_boot_mode != 1)) { + /* eMMC advanced mode initializatin done, notify ARM */ + i = npcpu_appcpu_mbx_send_notification(APPCPU_EVENT_EMMC_ADVANCE_EXIT,NULL); + if (i) + printk(KERN_ERR "can not send advanced mode finish notification to NPCPU \n"); + } +#endif // CONFIG_ARCH_GEN3 && CONFIG_CE_MAILBOX + +#if defined(CONFIG_ARCH_GEN3_MMC) + + /* eMMC advanced mode initializatin done, notify ATOM */ + if (host->card != NULL) + { + if (mmc_card_present(host->card)) + { + //printk("[PowerOn] mmc_rescan: remove MMC_CAP_NEEDS_POLL\n"); + host->caps &= ~MMC_CAP_NEEDS_POLL; /* Remvoe WA for Puma6 - After card is detected, we do not need to poll any nore */ + } + } + + if (!(host->caps & MMC_CAP_NEEDS_POLL)) + { + printk(KERN_INFO"NP-CPU MBX Send notification to APP-CPU - 'Card initialization complete'...\n"); + if (arm_atom_mbx_send_notification(ARM11_EVENT_EMMC_ADVANCE_INIT_EXIT,NULL)) + { + printk(KERN_ERR"[%s] NP-CPU MBOX error - Can not send advanced mode finish notification to APP-CPU.\n", __FUNCTION__); + } + + sync_printk(); + } +#endif // CONFIG_ARCH_GEN3_MMC +#endif // CONFIG_HW_MUTEXES +out: if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); } @@ -1726,6 +1932,10 @@ cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); +#ifdef CONFIG_ARCH_GEN3 + if (((struct sdhci_host *)mmc_priv(host))->quirks & SDHCI_QUIRK_NO_SUSPEND) + return err; +#endif mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->suspend) @@ -1762,6 +1972,10 @@ { int err = 0; +#ifdef CONFIG_ARCH_GEN3 + if (((struct sdhci_host *)mmc_priv(host))->quirks & SDHCI_QUIRK_NO_SUSPEND) + return err; +#endif mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { @@ -1795,6 +2009,11 @@ } EXPORT_SYMBOL(mmc_resume_host); +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) +extern struct mutex mmc_ioctl_mutex; +extern int mmc_in_suspend; +#endif + /* Do the card removal on suspend if card is assumed removeable * Do that in pm notifier while userspace isn't yet frozen, so we will be able to sync the card. @@ -1806,11 +2025,17 @@ notify_block, struct mmc_host, pm_notify); unsigned long flags; +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + mutex_lock(&mmc_ioctl_mutex); +#endif switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + mmc_in_suspend = 1; +#endif spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); @@ -1833,6 +2058,9 @@ case PM_POST_HIBERNATION: case PM_POST_RESTORE: +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + mmc_in_suspend = 0; +#endif spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; spin_unlock_irqrestore(&host->lock, flags); @@ -1840,6 +2068,10 @@ } +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + mutex_unlock(&mmc_ioctl_mutex); +#endif + return 0; } #endif