Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03e5732d authored by Dov Levenglick's avatar Dov Levenglick
Browse files

mmc: sdhci-msm: support multiple pm_qos configurations



Add support for multiple configurations of setting pm_qos
and have all pm_qos handled from the sdhci-msm driver.
This is used in order to support different hardware
architectures (cpu-to-cluster mapping), different pm_qos
requirements for read/write accesses or to compensate for
different scheduler schemes.

Change-Id: Iade1ec6058e56a7cc81322c2d997df76b7e760a6
Signed-off-by: default avatarDov Levenglick <dovl@codeaurora.org>
parent bdc10e75
Loading
Loading
Loading
Loading
+40 −7
Original line number Diff line number Diff line
@@ -58,9 +58,34 @@ Optional Properties:
				"HS200_1p2v" - indicates that host can support HS200 at 1.2v.
				"DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
				"DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
	- qcom,num-pm-qos-configs: allows for multiple configurations of pm_qos. if
				not provided, defaults to 1.
	- qcom,pm-qos-rw-policy: an array of strings the size of
				qcom,num-pm-qos-configs. legal values are "rw", "r" or "w"
				which indicate whether this configuration is specific to read
				or to write accesses. if not provided at all - all
				configurations default to "rw"
	- qcom,default-rd-pm-qos: default pm_qos configuration for read
				request. contains a string of numeric value (e.g. "1") or "cpu".
				if equals "cpu", if can't find exact match for read request
				in other configurations, searches again while ignoring
				qcom,pm-qos-rw-policy.
				if equals numeric value, must be less than
				qcom,num-pm-qos-configs. if not provided, defaults to "0".
	- qcom,default-wr-pm-qos: default pm_qos configuration for write
				request. contains a string of numeric value (e.g. "1") or "cpu".
				if equals "cpu", if can't find exact match for read request
				in other configurations, searches again while ignoring
				qcom,pm-qos-rw-policy.
				if equals numeric value, must be less than
				qcom,num-pm-qos-configs. if not provided, defaults to "0".
	- qcom,cpu-dma-latency-us: specifies acceptable DMA latency in microseconds.
				Default value is 200 ms. If this property specified as 0,
				then SDHC driver will not vote for PM QOS.
				Default value is 200 us. The value for each configuration can
				either be a single value or an array of 3 values corresponding
				to {SDHCI_PERFORMANCE_MODE, SDHCI_PERFORMANCE_MODE_INIT,
				SDHCI_POWER_SAVE_MODE}. If qcom,num-pm-qos-configs is larger
				than 1, provide multiple arrays - each must have the size of 3
				(although they may be duplicated values).
        - qcom,dat1-mpm-int:    specifies MPM interrupt number (e.g. sdhc_2 node below)
				corresponding to DAT1 line of SDHC (used only if slot has dedicated
				DAT1 MSM pin (not GPIO))
@@ -114,10 +139,14 @@ In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltag
	  all the cores in the little cluster.
	  The default CPU affinity mode is PM_QOS_REQ_AFFINE_IRQ to maintain
	  backward compatibility.
	  If qcom,num-pm-qos-configs is larger than 1, provide an array of strings.

	- qcom,cpu-affinity-mask: this is a bitmap that specifies little cluster CPU
	  cores used for PM QoS voting. This is parsed only for pm QoS request type of
	- qcom,cpu-affinity-mask: this is a bitmap that specifies the CPU cores used
	  for PM QoS voting. This is parsed only for pm QoS request type of
	  PM_QOS_REQ_AFFINE_CORES ("affine_cores").
	  If qcom,num-pm-qos-configs is larger than 1, provide an array of masks.
	  The values corresponding to configurations for which qcom,cpu-affinity is
	  not "affine_cores" will be ignored.

	- qcom,wakeup-on-idle: if configured, the mmcqd thread will call
	  set_wake_up_idle(), thereby voting for it to be called on idle CPUs.
@@ -152,9 +181,13 @@ Example:


                qcom,bus-width = <4>;
		qcom,cpu-dma-latency-us = <301>;
		qcom,cpu-affinity = "affine_cores";
		qcom,cpu-affinity-mask = <0x0f>;
		qcom,num-pm-qos-configs = <2>;
		qcom,default-rd-pm-qos-config = "0";
		qcom,default-wr-pm-qos-config = "cpu";
		qcom,pm-qos-rw-policy = "r", "w";
		qcom,cpu-dma-latency-us = <201 301 701>, <301 301 301>;
		qcom,cpu-affinity = "affine_cores", "irq";
		qcom,cpu-affinity-mask = <0x0f 0>;

		qcom,nonremovable;
		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+717 −88

File changed.

Preview size limit exceeded, changes collapsed.

+6 −100
Original line number Diff line number Diff line
@@ -171,33 +171,6 @@ static void sdhci_dumpregs(struct sdhci_host *host)
	pr_info(DRIVER_NAME ": ===========================================\n");
}

#define MAX_PM_QOS_TIMEOUT_VALUE	100000 /* 100 ms */
static ssize_t
show_sdhci_pm_qos_tout(struct device *dev, struct device_attribute *attr,
			char *buf)
{
	struct sdhci_host *host = dev_get_drvdata(dev);

	return snprintf(buf, PAGE_SIZE, "%d us\n", host->pm_qos_timeout_us);
}

static ssize_t
store_sdhci_pm_qos_tout(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct sdhci_host *host = dev_get_drvdata(dev);
	uint32_t value;
	unsigned long flags;

	if (!kstrtou32(buf, 0, &value)) {
		spin_lock_irqsave(&host->lock, flags);
		if (value <= MAX_PM_QOS_TIMEOUT_VALUE)
			host->pm_qos_timeout_us = value;
		spin_unlock_irqrestore(&host->lock, flags);
	}
	return count;
}

/*****************************************************************************\
 *                                                                           *
 * Low level functions                                                       *
@@ -1511,18 +1484,11 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
static int sdhci_enable(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
	u32 pol_index = 0;

	if (unlikely(!host->cpu_dma_latency_us))
		goto platform_bus_vote;

	if (host->cpu_dma_latency_tbl_sz > 1)
		pol_index = host->power_policy;
	if (!(host->when_to_vote & PM_QOS_VOTE_REQUEST) &&
	     host->ops->pm_qos_update)
		host->ops->pm_qos_update(host, NULL, SDHCI_PM_QOS_VOTE);

	pm_qos_update_request(&host->pm_qos_req_dma,
		host->cpu_dma_latency_us[pol_index]);

platform_bus_vote:
	if (host->ops->platform_bus_voting)
		host->ops->platform_bus_voting(host, 1);

@@ -1532,29 +1498,11 @@ platform_bus_vote:
static int sdhci_disable(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
	u32 pol_index = 0;

	if (unlikely(!host->cpu_dma_latency_us))
		goto platform_bus_vote;

	if (host->cpu_dma_latency_tbl_sz > 1)
		pol_index = host->power_policy;
	/*
	 * In performance mode, release QoS vote after a timeout to
	 * make sure back-to-back requests don't suffer from latencies
	 * that are involved to wake CPU from low power modes in cases
	 * where the CPU goes into low power mode as soon as QoS vote is
	 * released.
	 */
	if (host->power_policy == SDHCI_POWER_SAVE_MODE)
		pm_qos_update_request(&host->pm_qos_req_dma,
			PM_QOS_DEFAULT_VALUE);
	else
		pm_qos_update_request_timeout(&host->pm_qos_req_dma,
			host->cpu_dma_latency_us[pol_index],
			host->pm_qos_timeout_us);
	if (!(host->when_to_vote & PM_QOS_VOTE_REQUEST) &&
	     host->ops->pm_qos_update)
		host->ops->pm_qos_update(host, NULL, SDHCI_PM_QOS_UNVOTE);

platform_bus_vote:
	if (host->ops->platform_bus_voting)
		host->ops->platform_bus_voting(host, 0);

@@ -3452,29 +3400,6 @@ static int sdhci_is_adma2_64bit(struct sdhci_host *host)
}
#endif

#ifdef CONFIG_SMP
static void sdhci_set_pmqos_req_type(struct sdhci_host *host)
{
	/*
	 * The default request type PM_QOS_REQ_ALL_CORES is
	 * applicable to all CPU cores that are online and
	 * this would have a power impact when there are more
	 * number of CPUs. This new PM_QOS_REQ_AFFINE_IRQ request
	 * type shall update/apply the vote only to that CPU to
	 * which this IRQ's affinity is set to.
	 * PM_QOS_REQ_AFFINE_CORES request type is used for targets that have
	 * little cluster and will update/apply the vote to all the cores in
	 * the little cluster.
	 */
	if (host->pm_qos_req_dma.type == PM_QOS_REQ_AFFINE_IRQ)
		host->pm_qos_req_dma.irq = host->irq;
}
#else
static void sdhci_set_pmqos_req_type(struct sdhci_host *host)
{
}
#endif

int sdhci_add_host(struct sdhci_host *host)
{
	struct mmc_host *mmc;
@@ -4024,23 +3949,6 @@ int sdhci_add_host(struct sdhci_host *host)

	mmiowb();

	if (host->cpu_dma_latency_us) {
		host->pm_qos_timeout_us = 10000; /* default value */
		sdhci_set_pmqos_req_type(host);
		pm_qos_add_request(&host->pm_qos_req_dma,
				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);

		host->pm_qos_tout.show = show_sdhci_pm_qos_tout;
		host->pm_qos_tout.store = store_sdhci_pm_qos_tout;
		sysfs_attr_init(&host->pm_qos_tout.attr);
		host->pm_qos_tout.attr.name = "pm_qos_unvote_delay";
		host->pm_qos_tout.attr.mode = S_IRUGO | S_IWUSR;
		ret = device_create_file(mmc_dev(mmc), &host->pm_qos_tout);
		if (ret)
			pr_err("%s: cannot create pm_qos_unvote_delay %d\n",
					mmc_hostname(mmc), ret);
	}

	if (caps[0] & SDHCI_ASYNC_INTR)
		host->async_int_supp = true;

@@ -4096,8 +4004,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
	sdhci_update_power_policy(host, SDHCI_POWER_SAVE_MODE);
	sdhci_disable_card_detection(host);

	if (host->cpu_dma_latency_us)
		pm_qos_remove_request(&host->pm_qos_req_dma);
	mmc_remove_host(host->mmc);

#ifdef SDHCI_USE_LEDS_CLASS
+9 −0
Original line number Diff line number Diff line
@@ -277,6 +277,12 @@
#define SDHCI_DEFAULT_BOUNDARY_SIZE  (512 * 1024)
#define SDHCI_DEFAULT_BOUNDARY_ARG   (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)

enum sdhci_pm_qos_update {
	SDHCI_PM_QOS_VOTE,
	SDHCI_PM_QOS_UNVOTE,
	SDHCI_PM_QOS_UPDATE,
};

struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
	u32		(*read_l)(struct sdhci_host *host, int reg);
@@ -321,6 +327,9 @@ struct sdhci_ops {
					  bool enable,
					  u32 type);
	int	(*enable_controller_clock)(struct sdhci_host *host);
	void	(*pm_qos_update)(struct sdhci_host *host,
				 struct mmc_request *mrq,
				 enum sdhci_pm_qos_update type);
};

#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+3 −5
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ enum sdhci_power_policy {
	SDHCI_PERFORMANCE_MODE,
	SDHCI_PERFORMANCE_MODE_INIT,
	SDHCI_POWER_SAVE_MODE,
	SDHCI_NUM_PWR_POLICIES, /* MUST remain last */
};

struct sdhci_host {
@@ -264,11 +265,8 @@ struct sdhci_host {
#define SDHCI_TUNING_MODE_1	0
	struct timer_list	tuning_timer;	/* Timer for tuning */

	unsigned int *cpu_dma_latency_us;
	unsigned int cpu_dma_latency_tbl_sz;
	struct pm_qos_request pm_qos_req_dma;
	unsigned int pm_qos_timeout_us;         /* timeout for PM QoS request */
	struct device_attribute pm_qos_tout;
	unsigned int		when_to_vote;
#define PM_QOS_VOTE_REQUEST	BIT(0)		/* vote for each request */

	struct sdhci_next next_data;
	ktime_t data_start_time;