These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / mmc / core / host.c
index 8be0df7..da950c4 100644 (file)
@@ -61,245 +61,89 @@ void mmc_unregister_host_class(void)
        class_unregister(&mmc_host_class);
 }
 
-#ifdef CONFIG_MMC_CLKGATE
-static ssize_t clkgate_delay_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+void mmc_retune_enable(struct mmc_host *host)
 {
-       struct mmc_host *host = cls_dev_to_mmc_host(dev);
-       return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
+       host->can_retune = 1;
+       if (host->retune_period)
+               mod_timer(&host->retune_timer,
+                         jiffies + host->retune_period * HZ);
 }
 
-static ssize_t clkgate_delay_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+void mmc_retune_disable(struct mmc_host *host)
 {
-       struct mmc_host *host = cls_dev_to_mmc_host(dev);
-       unsigned long flags, value;
-
-       if (kstrtoul(buf, 0, &value))
-               return -EINVAL;
-
-       spin_lock_irqsave(&host->clk_lock, flags);
-       host->clkgate_delay = value;
-       spin_unlock_irqrestore(&host->clk_lock, flags);
-       return count;
+       host->can_retune = 0;
+       del_timer_sync(&host->retune_timer);
+       host->retune_now = 0;
+       host->need_retune = 0;
 }
 
-/*
- * Enabling clock gating will make the core call out to the host
- * once up and once down when it performs a request or card operation
- * intermingled in any fashion. The driver will see this through
- * set_ios() operations with ios.clock field set to 0 to gate (disable)
- * the block clock, and to the old frequency to enable it again.
- */
-static void mmc_host_clk_gate_delayed(struct mmc_host *host)
+void mmc_retune_timer_stop(struct mmc_host *host)
 {
-       unsigned long tick_ns;
-       unsigned long freq = host->ios.clock;
-       unsigned long flags;
-
-       if (!freq) {
-               pr_debug("%s: frequency set to 0 in disable function, "
-                        "this means the clock is already disabled.\n",
-                        mmc_hostname(host));
-               return;
-       }
-       /*
-        * New requests may have appeared while we were scheduling,
-        * then there is no reason to delay the check before
-        * clk_disable().
-        */
-       spin_lock_irqsave(&host->clk_lock, flags);
-
-       /*
-        * Delay n bus cycles (at least 8 from MMC spec) before attempting
-        * to disable the MCI block clock. The reference count may have
-        * gone up again after this delay due to rescheduling!
-        */
-       if (!host->clk_requests) {
-               spin_unlock_irqrestore(&host->clk_lock, flags);
-               tick_ns = DIV_ROUND_UP(1000000000, freq);
-               ndelay(host->clk_delay * tick_ns);
-       } else {
-               /* New users appeared while waiting for this work */
-               spin_unlock_irqrestore(&host->clk_lock, flags);
-               return;
-       }
-       mutex_lock(&host->clk_gate_mutex);
-       spin_lock_irqsave(&host->clk_lock, flags);
-       if (!host->clk_requests) {
-               spin_unlock_irqrestore(&host->clk_lock, flags);
-               /* This will set host->ios.clock to 0 */
-               mmc_gate_clock(host);
-               spin_lock_irqsave(&host->clk_lock, flags);
-               pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
-       }
-       spin_unlock_irqrestore(&host->clk_lock, flags);
-       mutex_unlock(&host->clk_gate_mutex);
+       del_timer_sync(&host->retune_timer);
 }
+EXPORT_SYMBOL(mmc_retune_timer_stop);
 
-/*
- * Internal work. Work to disable the clock at some later point.
- */
-static void mmc_host_clk_gate_work(struct work_struct *work)
+void mmc_retune_hold(struct mmc_host *host)
 {
-       struct mmc_host *host = container_of(work, struct mmc_host,
-                                             clk_gate_work.work);
-
-       mmc_host_clk_gate_delayed(host);
+       if (!host->hold_retune)
+               host->retune_now = 1;
+       host->hold_retune += 1;
 }
 
-/**
- *     mmc_host_clk_hold - ungate hardware MCI clocks
- *     @host: host to ungate.
- *
- *     Makes sure the host ios.clock is restored to a non-zero value
- *     past this call. Increase clock reference count and ungate clock
- *     if we're the first user.
- */
-void mmc_host_clk_hold(struct mmc_host *host)
+void mmc_retune_release(struct mmc_host *host)
 {
-       unsigned long flags;
-
-       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
-       cancel_delayed_work_sync(&host->clk_gate_work);
-       mutex_lock(&host->clk_gate_mutex);
-       spin_lock_irqsave(&host->clk_lock, flags);
-       if (host->clk_gated) {
-               spin_unlock_irqrestore(&host->clk_lock, flags);
-               mmc_ungate_clock(host);
-               spin_lock_irqsave(&host->clk_lock, flags);
-               pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
-       }
-       host->clk_requests++;
-       spin_unlock_irqrestore(&host->clk_lock, flags);
-       mutex_unlock(&host->clk_gate_mutex);
+       if (host->hold_retune)
+               host->hold_retune -= 1;
+       else
+               WARN_ON(1);
 }
 
-/**
- *     mmc_host_may_gate_card - check if this card may be gated
- *     @card: card to check.
- */
-static bool mmc_host_may_gate_card(struct mmc_card *card)
+int mmc_retune(struct mmc_host *host)
 {
-       /* If there is no card we may gate it */
-       if (!card)
-               return true;
-       /*
-        * Don't gate SDIO cards! These need to be clocked at all times
-        * since they may be independent systems generating interrupts
-        * and other events. The clock requests counter from the core will
-        * go down to zero since the core does not need it, but we will not
-        * gate the clock, because there is somebody out there that may still
-        * be using it.
-        */
-       return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
-}
+       bool return_to_hs400 = false;
+       int err;
 
-/**
- *     mmc_host_clk_release - gate off hardware MCI clocks
- *     @host: host to gate.
- *
- *     Calls the host driver with ios.clock set to zero as often as possible
- *     in order to gate off hardware MCI clocks. Decrease clock reference
- *     count and schedule disabling of clock.
- */
-void mmc_host_clk_release(struct mmc_host *host)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&host->clk_lock, flags);
-       host->clk_requests--;
-       if (mmc_host_may_gate_card(host->card) &&
-           !host->clk_requests)
-               schedule_delayed_work(&host->clk_gate_work,
-                                     msecs_to_jiffies(host->clkgate_delay));
-       spin_unlock_irqrestore(&host->clk_lock, flags);
-}
+       if (host->retune_now)
+               host->retune_now = 0;
+       else
+               return 0;
 
-/**
- *     mmc_host_clk_rate - get current clock frequency setting
- *     @host: host to get the clock frequency for.
- *
- *     Returns current clock frequency regardless of gating.
- */
-unsigned int mmc_host_clk_rate(struct mmc_host *host)
-{
-       unsigned long freq;
-       unsigned long flags;
+       if (!host->need_retune || host->doing_retune || !host->card)
+               return 0;
 
-       spin_lock_irqsave(&host->clk_lock, flags);
-       if (host->clk_gated)
-               freq = host->clk_old;
-       else
-               freq = host->ios.clock;
-       spin_unlock_irqrestore(&host->clk_lock, flags);
-       return freq;
-}
+       host->need_retune = 0;
 
-/**
- *     mmc_host_clk_init - set up clock gating code
- *     @host: host with potential clock to control
- */
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
-       host->clk_requests = 0;
-       /* Hold MCI clock for 8 cycles by default */
-       host->clk_delay = 8;
-       /*
-        * Default clock gating delay is 0ms to avoid wasting power.
-        * This value can be tuned by writing into sysfs entry.
-        */
-       host->clkgate_delay = 0;
-       host->clk_gated = false;
-       INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
-       spin_lock_init(&host->clk_lock);
-       mutex_init(&host->clk_gate_mutex);
-}
+       host->doing_retune = 1;
 
-/**
- *     mmc_host_clk_exit - shut down clock gating code
- *     @host: host with potential clock to control
- */
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
-       /*
-        * Wait for any outstanding gate and then make sure we're
-        * ungated before exiting.
-        */
-       if (cancel_delayed_work_sync(&host->clk_gate_work))
-               mmc_host_clk_gate_delayed(host);
-       if (host->clk_gated)
-               mmc_host_clk_hold(host);
-       /* There should be only one user now */
-       WARN_ON(host->clk_requests > 1);
-}
+       if (host->ios.timing == MMC_TIMING_MMC_HS400) {
+               err = mmc_hs400_to_hs200(host->card);
+               if (err)
+                       goto out;
 
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
-{
-       host->clkgate_delay_attr.show = clkgate_delay_show;
-       host->clkgate_delay_attr.store = clkgate_delay_store;
-       sysfs_attr_init(&host->clkgate_delay_attr.attr);
-       host->clkgate_delay_attr.attr.name = "clkgate_delay";
-       host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
-       if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
-               pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
-                               mmc_hostname(host));
-}
-#else
+               return_to_hs400 = true;
 
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
-}
+               if (host->ops->prepare_hs400_tuning)
+                       host->ops->prepare_hs400_tuning(host, &host->ios);
+       }
 
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
+       err = mmc_execute_tuning(host->card);
+       if (err)
+               goto out;
+
+       if (return_to_hs400)
+               err = mmc_hs200_to_hs400(host->card);
+out:
+       host->doing_retune = 0;
+
+       return err;
 }
 
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+static void mmc_retune_timer(unsigned long data)
 {
-}
+       struct mmc_host *host = (struct mmc_host *)data;
 
-#endif
+       mmc_retune_needed(host);
+}
 
 /**
  *     mmc_of_parse() - parse host's device-tree node
@@ -314,7 +158,7 @@ int mmc_of_parse(struct mmc_host *host)
 {
        struct device_node *np;
        u32 bus_width;
-       int len, ret;
+       int ret;
        bool cd_cap_invert, cd_gpio_invert = false;
        bool ro_cap_invert, ro_gpio_invert = false;
 
@@ -361,19 +205,19 @@ int mmc_of_parse(struct mmc_host *host)
         */
 
        /* Parse Card Detection */
-       if (of_find_property(np, "non-removable", &len)) {
+       if (of_property_read_bool(np, "non-removable")) {
                host->caps |= MMC_CAP_NONREMOVABLE;
        } else {
                cd_cap_invert = of_property_read_bool(np, "cd-inverted");
 
-               if (of_find_property(np, "broken-cd", &len))
+               if (of_property_read_bool(np, "broken-cd"))
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
                ret = mmc_gpiod_request_cd(host, "cd", 0, true,
                                           0, &cd_gpio_invert);
                if (!ret)
                        dev_info(host->parent, "Got CD GPIO\n");
-               else if (ret != -ENOENT)
+               else if (ret != -ENOENT && ret != -ENOSYS)
                        return ret;
 
                /*
@@ -397,48 +241,53 @@ int mmc_of_parse(struct mmc_host *host)
        ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
        if (!ret)
                dev_info(host->parent, "Got WP GPIO\n");
-       else if (ret != -ENOENT)
+       else if (ret != -ENOENT && ret != -ENOSYS)
                return ret;
 
+       if (of_property_read_bool(np, "disable-wp"))
+               host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
+
        /* See the comment on CD inversion above */
        if (ro_cap_invert ^ ro_gpio_invert)
                host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (of_find_property(np, "cap-sd-highspeed", &len))
+       if (of_property_read_bool(np, "cap-sd-highspeed"))
                host->caps |= MMC_CAP_SD_HIGHSPEED;
-       if (of_find_property(np, "cap-mmc-highspeed", &len))
+       if (of_property_read_bool(np, "cap-mmc-highspeed"))
                host->caps |= MMC_CAP_MMC_HIGHSPEED;
-       if (of_find_property(np, "sd-uhs-sdr12", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr12"))
                host->caps |= MMC_CAP_UHS_SDR12;
-       if (of_find_property(np, "sd-uhs-sdr25", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr25"))
                host->caps |= MMC_CAP_UHS_SDR25;
-       if (of_find_property(np, "sd-uhs-sdr50", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr50"))
                host->caps |= MMC_CAP_UHS_SDR50;
-       if (of_find_property(np, "sd-uhs-sdr104", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr104"))
                host->caps |= MMC_CAP_UHS_SDR104;
-       if (of_find_property(np, "sd-uhs-ddr50", &len))
+       if (of_property_read_bool(np, "sd-uhs-ddr50"))
                host->caps |= MMC_CAP_UHS_DDR50;
-       if (of_find_property(np, "cap-power-off-card", &len))
+       if (of_property_read_bool(np, "cap-power-off-card"))
                host->caps |= MMC_CAP_POWER_OFF_CARD;
-       if (of_find_property(np, "cap-sdio-irq", &len))
+       if (of_property_read_bool(np, "cap-mmc-hw-reset"))
+               host->caps |= MMC_CAP_HW_RESET;
+       if (of_property_read_bool(np, "cap-sdio-irq"))
                host->caps |= MMC_CAP_SDIO_IRQ;
-       if (of_find_property(np, "full-pwr-cycle", &len))
+       if (of_property_read_bool(np, "full-pwr-cycle"))
                host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
-       if (of_find_property(np, "keep-power-in-suspend", &len))
+       if (of_property_read_bool(np, "keep-power-in-suspend"))
                host->pm_caps |= MMC_PM_KEEP_POWER;
-       if (of_find_property(np, "enable-sdio-wakeup", &len))
+       if (of_property_read_bool(np, "enable-sdio-wakeup"))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
-       if (of_find_property(np, "mmc-ddr-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-ddr-1_8v"))
                host->caps |= MMC_CAP_1_8V_DDR;
-       if (of_find_property(np, "mmc-ddr-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-ddr-1_2v"))
                host->caps |= MMC_CAP_1_2V_DDR;
-       if (of_find_property(np, "mmc-hs200-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-hs200-1_8v"))
                host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
-       if (of_find_property(np, "mmc-hs200-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-hs200-1_2v"))
                host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
-       if (of_find_property(np, "mmc-hs400-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-hs400-1_8v"))
                host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
-       if (of_find_property(np, "mmc-hs400-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-hs400-1_2v"))
                host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 
        host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
@@ -496,14 +345,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
                return NULL;
        }
 
-       mmc_host_clk_init(host);
-
        spin_lock_init(&host->lock);
        init_waitqueue_head(&host->wq);
        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
 #ifdef CONFIG_PM
        host->pm_notify.notifier_call = mmc_pm_notify;
 #endif
+       setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
 
        /*
         * By default, hosts do not support SGIO or large requests.
@@ -545,7 +393,6 @@ int mmc_add_host(struct mmc_host *host)
 #ifdef CONFIG_DEBUG_FS
        mmc_add_host_debugfs(host);
 #endif
-       mmc_host_clk_sysfs_init(host);
 
        mmc_start_host(host);
        register_pm_notifier(&host->pm_notify);
@@ -575,8 +422,6 @@ void mmc_remove_host(struct mmc_host *host)
        device_del(&host->class_dev);
 
        led_trigger_unregister_simple(host->led);
-
-       mmc_host_clk_exit(host);
 }
 
 EXPORT_SYMBOL(mmc_remove_host);