Re: [PATCH v4 4/8] qcom: spm-devices: Add SPM device manager for the SoC

2014-08-26 Thread Lina Iyer

On Mon, Aug 25, 2014 at 07:17:15PM -0700, Stephen Boyd wrote:

On 08/25/14 17:31, Lina Iyer wrote:

On Mon, Aug 25, 2014 at 04:40:33PM -0700, Stephen Boyd wrote:

On 08/19/14 15:15, Lina Iyer wrote:

diff --git a/Documentation/devicetree/bindings/arm/msm/spm.txt
b/Documentation/devicetree/bindings/arm/msm/spm.txt
new file mode 100644
index 000..318e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/spm.txt


We already have a binding document for SAW. Please add stuff there
because SPM is just a component of SAW.


I agree that SPM is just a component of the SAW. But the document there
seems to indicate regulator details, totally unrelated to the actual SAW
hardware functionality.


Huh? The SAW binding should be extended with whatever properties are
necessary. Probably the only thing we need is the delays. Everything
else can be determined from the compatible?


Thats not true. There are many voltage related properties that are yet
to come. Not everything else can be determined from the compatible flag.
The idea behind having SPM nodes in the DT is that different SoCs may
have the same version of SPM but may have to talk to different
components. The delays, the PMIC register and the PMIC data all change
with the components that SPM communicates.


SAW has a connection to the PMIC, does it not? If it isn't directly
connected we can come up with a different name for the node, but just
because the node name in the example is misleading doesn't mean we
should completely disregard what we already have.


Yes the SAW has a connection to the PMIC. But what the nodes represent
are just regulator nodes and have no bearing on the SAW. You could use
SPMI/I2C writes to convey the same value without having to go through
SAW using those nodes. I have no reasonable understanding as to why they
are called SAW regulators in the first place. They are just regulators.
The mechanism of using SPM to communicate with the PMIC does not exist
in the kernel and is not part of those nodes. So adding to that
confusion wasn't a wise choice for me.




@@ -0,0 +1,47 @@
+* Subsystem Power Manager (SAW2)
+
+S4 generation of MSMs have SPM hardware blocks to control the
Application
+Processor Sub-System power. These SPM blocks run individual state
machine
+to determine what the core (L2 or Krait/Scorpion) would do when the
WFI
+instruction is executed by the core.
+
+The devicetree representation of the SPM block should be:
+
+Required properties
+
+- compatible: Could be one of -
+qcom,spm-v2.1
+qcom,spm-v3.0
+- reg: The physical address and the size of the SPM's memory mapped
registers
+- qcom,cpu: phandle for the CPU that the SPM block is attached to.
+This field is required on only for SPMs that control the CPU.


We have a phandle from the CPU/L2 to the SAW, so this isn't necessary.


Sorry, I dont understand. Care to explain pls? Its necessary to know
what SPM instance controls which CPU or L2, so as to pick the right SPM
device to configure.


We have a phandle in the CPU nodes pointing to the SAW that is
associated with that CPU (qcom,saw). SPM is a part of a SAW. Thus there
is no need for this qcom,cpu property once the SAW node is used.
Instead, we can search the CPU and cache nodes for a qcom,saw that
matches the of_node for the platform device we're probing.


I agree thats doable. The cpu node can point to the SPM node or the
otherway as it is done here. I dont have a strong preference eitherway.
Lets resolve the earlier and we may have a solution for this, in our
hands.




+- qcom,saw2-cfg: SAW2 configuration register


Why? Compatible should indicate where this register is.


There are multiple versions of saw handled by the same driver and
distinguished by the version register. These SAW revisions differ in the
register offset organization. The variable holds the value to be
configured in the saw2-cfg register. I will update the documentation to
be more clear.

+- qcom,saw2-spm-ctl: The SPM control register


Why? Compatible should indicate where this register is.


See above.


Ah this is more register jam table in DT? cfg should probably be
described in desired clock rate and then the driver can figure out the
value by multiplying that the input clock rate. spm-ctl looks like it's
usually used to describe enable, which seems rather obvious. Why isn't
the driver always writing the enable bit (bit 0)?


Kumar already had suggested that. I changed the code, but forgot to
update the documentation, which I noticed and amended in my local tree.
Waiting for some more comments and some changes in cpuidle stuff before
I submit the next rev. Thanks.
That said, figuring out the input clock rate and the multiplication is
still unnecessary. There are not much options on the hardware to change
clock rate and different parameters that will work well on a SoC. SPMs
are generic state machines and are designed to support multiple QCOM
SoCs and hence the configuration options. They dont generally

Re: [PATCH 8/8] msm: scm: Move the scm driver to drivers/soc/qcom

2014-08-04 Thread Lina Iyer
On Mon, 4 Aug 2014, Stephen Boyd wrote:

 Architectural changes in the ARM Linux kernel tree mandate
 the eventual removal of the mach-* directories. Move the
 scm driver to drivers/soc/qcom and the scm header to
 include/soc/qcom to support that removal.
 
 Signed-off-by: Stephen Boyd sb...@codeaurora.org
 ---
  arch/arm/mach-qcom/Kconfig | 3 ---
  arch/arm/mach-qcom/Makefile| 4 +---
  arch/arm/mach-qcom/scm-boot.c  | 2 +-

 diff --git a/arch/arm/mach-qcom/scm.h b/include/soc/qcom/scm.h
 similarity index 100%
 rename from arch/arm/mach-qcom/scm.h
 rename to include/soc/qcom/scm.h

Could we move scm-boot.c as well to drivers/soc/qcom and scm-boot.h to 
include/soc/qcom ?
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 8/8] msm: scm: Move the scm driver to drivers/soc/qcom

2014-08-05 Thread Lina Iyer



On Tue, 5 Aug 2014, Bjorn Andersson wrote:

 On Mon, Aug 4, 2014 at 9:07 PM, Lina Iyer lina.i...@linaro.org wrote:
  On Mon, 4 Aug 2014, Stephen Boyd wrote:
 [...]
  Could we move scm-boot.c as well to drivers/soc/qcom and scm-boot.h to 
  include/soc/qcom ?
 
 Yes, we can do that.
 
 But as of now we seem to only have one caller of this wrapper, so
 maybe we could move the functionality into platsmp.c and drop the file
 instead?
I am working on cpuidle drivers for QCOM targets and would very much
like the scm-boot to be accessible from drivers/soc/qcom.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 4/4] QoS: Enable PM QoS requests to apply only on smp_affinity of an IRQ

2014-08-27 Thread Lina Iyer
Based on original work by pchid...@codeaurora.org.

QoS requests that need to track an IRQ can be set to apply only on the
cpus to which the IRQ's smp_affinity attribute is set to. The PM QoS
framework will automatically track IRQ migration between the cores. The
QoS is updated to be applied only to the core(s) that the IRQ has been
migrated to.

The userspace sysfs interface does not support IRQ affinity.

Signed-off-by: Praveen Chidambaram pchid...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
[lina.iyer: Split the change from a previous change, add commit text]

diff --git a/Documentation/power/pm_qos_interface.txt 
b/Documentation/power/pm_qos_interface.txt
index c129517..32b864d 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -47,8 +47,10 @@ applies to all cores. However, the driver can also specify a 
request type to
 be either of
 PM_QOS_REQ_ALL_CORES,
 PM_QOS_REQ_AFFINE_CORES,
+PM_QOS_REQ_AFFINE_IRQ,
 
-Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES.
+Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES and specify
+the IRQ number with PM_QOS_REQ_AFFINE_IRQ.
 
 void pm_qos_update_request(handle, new_target_value):
 Will update the list element pointed to by the handle with the new target value
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index a3aa5b5..68b16b8 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -11,6 +11,7 @@
 #include linux/workqueue.h
 #include linux/cpumask.h
 #include linux/interrupt.h
+#include linux/completion.h
 
 enum {
PM_QOS_RESERVED = 0,
@@ -45,12 +46,16 @@ enum pm_qos_flags_status {
 enum pm_qos_req_type {
PM_QOS_REQ_ALL_CORES = 0,
PM_QOS_REQ_AFFINE_CORES,
+   PM_QOS_REQ_AFFINE_IRQ,
 };
 
 struct pm_qos_request {
enum pm_qos_req_type type;
struct cpumask cpus_affine;
+   uint32_t irq;
/* Internal structure members */
+   struct irq_affinity_notify irq_notify;
+   struct completion irq_released;
struct plist_node node;
int pm_qos_class;
struct delayed_work work; /* for pm_qos_update_request_timeout */
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 27f84a2..c10e8bc 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -41,6 +41,9 @@
 #include linux/platform_device.h
 #include linux/init.h
 #include linux/kernel.h
+#include linux/irq.h
+#include linux/irqdesc.h
+#include linux/delay.h
 
 #include linux/uaccess.h
 #include linux/export.h
@@ -412,6 +415,37 @@ static void pm_qos_work_fn(struct work_struct *work)
__pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
 }
 
+static void pm_qos_irq_release(struct kref *ref)
+{
+   unsigned long flags;
+   struct irq_affinity_notify *notify = container_of(ref,
+   struct irq_affinity_notify, kref);
+   struct pm_qos_request *req = container_of(notify,
+   struct pm_qos_request, irq_notify);
+
+   spin_lock_irqsave(pm_qos_lock, flags);
+   cpumask_clear(req-cpus_affine);
+   spin_unlock_irqrestore(pm_qos_lock, flags);
+
+   complete(req-irq_released);
+}
+
+static void pm_qos_irq_notify(struct irq_affinity_notify *notify,
+   const cpumask_t *mask)
+{
+   unsigned long flags;
+   struct pm_qos_request *req = container_of(notify,
+   struct pm_qos_request, irq_notify);
+   struct pm_qos_constraints *c =
+   pm_qos_array[req-pm_qos_class]-constraints;
+
+   spin_lock_irqsave(pm_qos_lock, flags);
+   cpumask_copy(req-cpus_affine, mask);
+   spin_unlock_irqrestore(pm_qos_lock, flags);
+
+   pm_qos_update_target(c, req, PM_QOS_UPDATE_REQ, req-node.prio);
+}
+
 /**
  * pm_qos_add_request - inserts new qos request into the list
  * @req: pointer to a preallocated handle
@@ -445,6 +479,34 @@ void pm_qos_add_request(struct pm_qos_request *req,
}
break;
 
+   case PM_QOS_REQ_AFFINE_IRQ:
+   if (irq_can_set_affinity(req-irq)) {
+   int ret = 0;
+   struct irq_desc *desc = irq_to_desc(req-irq);
+   struct cpumask *mask = desc-irq_data.affinity;
+
+   /* Get the current affinity */
+   cpumask_copy(req-cpus_affine, mask);
+   req-irq_notify.irq = req-irq;
+   req-irq_notify.notify = pm_qos_irq_notify;
+   req-irq_notify.release = pm_qos_irq_release;
+
+   ret = irq_set_affinity_notifier(req-irq,
+   req-irq_notify);
+   if (ret) {
+   WARN(1, KERN_ERR IRQ affinity notify set 
failed\n);
+   req-type = PM_QOS_REQ_ALL_CORES;
+   cpumask_setall(req-cpus_affine

[PATCH v3 2/4] QoS: Enhance framework to support per-cpu PM QoS request

2014-08-27 Thread Lina Iyer
From: Praveen Chidambaram pchid...@codeaurora.org

QoS request can be better optimized if the request can be set only for
the required cpus and not all cpus. This helps save power on other
cores, while still guaranteeing the quality of service on the desired
cores.

Add a new enumeration to specify the PM QoS request type. The enums help
specify what is the intended target cpu of the request.

Enhance the QoS constraints data structures to support target value for
each core. Requests specify if the QoS is applicable to all cores
(default) or to a selective subset of the cores or to a core(s).

Idle and interested drivers can request a PM QoS value for a constraint
across all cpus, or a specific cpu or a set of cpus. Separate APIs have
been added to request for individual cpu or a cpumask.  The default
behaviour of PM QoS is maintained i.e, requests that do not specify a
type of the request will continue to be effected on all cores.

The userspace sysfs interface does not support setting cpumask of a PM
QoS request.

Signed-off-by: Praveen Chidambaram pchid...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
[lina.iyer: rework, add commit text, split changes into multiple patches]

diff --git a/Documentation/power/pm_qos_interface.txt 
b/Documentation/power/pm_qos_interface.txt
index a5da5c7..c129517 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -41,6 +41,15 @@ registered notifiers are called only if the target value is 
now different.
 Clients of pm_qos need to save the returned handle for future use in other
 pm_qos API functions.
 
+The handle is a pm_qos_request object. By default the request object sets the
+request type to PM_QOS_REQ_ALL_CORES, in which case, the PM QoS request
+applies to all cores. However, the driver can also specify a request type to
+be either of
+PM_QOS_REQ_ALL_CORES,
+PM_QOS_REQ_AFFINE_CORES,
+
+Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES.
+
 void pm_qos_update_request(handle, new_target_value):
 Will update the list element pointed to by the handle with the new target value
 and recompute the new aggregated target, calling the notification tree if the
@@ -54,6 +63,13 @@ the request.
 int pm_qos_request(param_class):
 Returns the aggregated value for a given PM QoS class.
 
+int pm_qos_request_for_cpu(param_class, cpu):
+Returns the aggregated value for a given PM QoS class for the specified cpu.
+
+int pm_qos_request_for_cpumask(param_class, cpumask):
+Returns the aggregated value for a given PM QoS class for the specified
+cpumask.
+
 int pm_qos_request_active(handle):
 Returns if the request is still active, i.e. it has not been removed from a
 PM QoS class constraints list.
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index e1b763d..a3aa5b5 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -9,6 +9,8 @@
 #include linux/miscdevice.h
 #include linux/device.h
 #include linux/workqueue.h
+#include linux/cpumask.h
+#include linux/interrupt.h
 
 enum {
PM_QOS_RESERVED = 0,
@@ -40,7 +42,15 @@ enum pm_qos_flags_status {
 #define PM_QOS_FLAG_NO_POWER_OFF   (1  0)
 #define PM_QOS_FLAG_REMOTE_WAKEUP  (1  1)
 
+enum pm_qos_req_type {
+   PM_QOS_REQ_ALL_CORES = 0,
+   PM_QOS_REQ_AFFINE_CORES,
+};
+
 struct pm_qos_request {
+   enum pm_qos_req_type type;
+   struct cpumask cpus_affine;
+   /* Internal structure members */
struct plist_node node;
int pm_qos_class;
struct delayed_work work; /* for pm_qos_update_request_timeout */
@@ -80,6 +90,7 @@ enum pm_qos_type {
 struct pm_qos_constraints {
struct plist_head list;
s32 target_value;   /* Do not change to 64 bit */
+   s32 target_per_cpu[NR_CPUS];
s32 default_value;
s32 no_constraint_value;
enum pm_qos_type type;
@@ -127,6 +138,8 @@ void pm_qos_update_request_timeout(struct pm_qos_request 
*req,
 void pm_qos_remove_request(struct pm_qos_request *req);
 
 int pm_qos_request(int pm_qos_class);
+int pm_qos_request_for_cpu(int pm_qos_class, int cpu);
+int pm_qos_request_for_cpumask(int pm_qos_class, struct cpumask *mask);
 int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_request_active(struct pm_qos_request *req);
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index d0b9c0f..27f84a2 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -65,6 +65,8 @@ static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
 static struct pm_qos_constraints cpu_dma_constraints = {
.list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+   .target_per_cpu = { [0 ... (NR_CPUS - 1)] =
+   PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE },
.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE

[PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-08-27 Thread Lina Iyer
PM QoS and other idle frameworks can do a better job of addressing power
and performance requirements for a cpu, knowing the IRQs that are
affine to that cpu. If a performance request is placed against serving
the IRQ faster and if the IRQ is affine to a set of cpus, then setting
the performance requirements only on those cpus help save power on the
rest of the cpus. PM QoS framework is one such framework interested in
knowing the smp_affinity of an IRQ and the change notificiation in this
regard. QoS requests for the CPU_DMA_LATENCY constraint currently apply
to all cpus, but when attached to an IRQ, can be applied only to the set
of cpus that IRQ's smp_affinity is set to. This allows other cpus to
enter deeper sleep states to save power. More than one framework/driver
can be interested in such information.

The current implementation allows only a single notification callback
whenever the IRQ's SMP affinity is changed. Adding a second notification
punts the existing notifier function out of registration.  Add a list of
notifiers, allowing multiple clients to register for irq affinity
notifications.

The kref object associated with the struct irq_affinity_notify was used
to prevent the notifier object from being released if there is a pending
notification. It was incremented before the work item was scheduled and
was decremented when the notification was completed. If the kref count
was zero at the end of it, the release function gets a callback allowing
the module to release the irq_affinity_notify memory. This works well
for a single notification. When multiple clients are registered, no
single kref object can be used. Hence, the work function when scheduled,
will increase the kref count using the kref_get_unless_zero(), so if the
module had already unregistered the irq_affinity_notify object while the
work function was scheduled, it will not be notified.

Signed-off-by: Lina Iyer lina.i...@linaro.org

diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c 
b/drivers/infiniband/hw/qib/qib_iba7322.c
index a7eb325..62cb77d 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -3345,9 +3345,7 @@ static void reset_dca_notifier(struct qib_devdata *dd, 
struct qib_msix_entry *m)
Disabling notifier on HCA %d irq %d\n,
dd-unit,
m-msix.vector);
-   irq_set_affinity_notifier(
-   m-msix.vector,
-   NULL);
+   irq_release_affinity_notifier(m-notifier);
m-notifier = NULL;
 }
 
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 698ad05..c1e227c 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -203,7 +203,7 @@ static inline int check_wakeup_irqs(void) { return 0; }
  * struct irq_affinity_notify - context for notification of IRQ affinity 
changes
  * @irq:   Interrupt to which notification applies
  * @kref:  Reference count, for internal use
- * @work:  Work item, for internal use
+ * @list:  Add to the notifier list, for internal use
  * @notify:Function to be called on change.  This will be
  * called in process context.
  * @release:   Function to be called on release.  This will be
@@ -214,7 +214,7 @@ static inline int check_wakeup_irqs(void) { return 0; }
 struct irq_affinity_notify {
unsigned int irq;
struct kref kref;
-   struct work_struct work;
+   struct list_head list;
void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask);
void (*release)(struct kref *ref);
 };
@@ -265,6 +265,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const 
struct cpumask *m);
 extern int
 irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify 
*notify);
 
+extern int
+irq_release_affinity_notifier(struct irq_affinity_notify *notify);
 #else /* CONFIG_SMP */
 
 static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)
@@ -295,6 +297,12 @@ irq_set_affinity_notifier(unsigned int irq, struct 
irq_affinity_notify *notify)
 {
return 0;
 }
+
+static inline int
+irq_release_affinity_notifier(struct irq_affinity_notify *notify)
+{
+   return 0;
+}
 #endif /* CONFIG_SMP */
 
 /*
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 472c021..db3509e 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -31,7 +31,8 @@ struct irq_desc;
  * @threads_handled_last: comparator field for deferred spurious detection of 
theraded handlers
  * @lock:  locking for SMP
  * @affinity_hint: hint to user space for preferred irq affinity
- * @affinity_notify:   context for notification of affinity changes
+ * @affinity_notify:   list of notification clients for affinity changes
+ * @affinity_work: Work queue for handling affinity change notifications
  * @pending_mask:  pending rebalanced interrupts
  * @threads_oneshot:   bitfield

[PATCH v3 0/4] PM QoS: per-cpu PM QoS support

2014-08-27 Thread Lina Iyer
Changes since v2:
[ http://marc.info/?l=linux-pmm=140794570012619w=2 ]
- Amend commit texts

This patchset enables drivers to set per-cpu PM QoS. PM QoS requests currently
apply to all cpus. However, drivers may be interested in only a few cpu(s) that
need to gaurantee the QoS requirement. The reason being, some requests may be
needed only to allow a quicker response to an IRQ, while requests may apply to
a certain cpu or a cluster of cpus, as dictated by an usecase. For example, in
ARM architectures, it may be benefical to set a QoS requirement to handle use
cases on big/Little cluster, while the other cluster can be in the deepest idle
state it can be.

An intended application of this feature could be the cpuidle governor. For
example, governor can now look at a CPU_DMA_LATENCY request only for that cpu
when deciding the allowable C-States. In a clustered environment, the governor
would look at the QoS request for a set of cpus before deciding the cluster's
low power mode.

With these requirements in mind, the patches do the following -

- Reorganize the PM QoS and dev-PM QoS frameworks to pass around data structures
rather than member variables. Do not want to pass plist around. It is much more
scalable, if we pass the pm_qos_request object rather than its member.

- Enhance PM QoS framework to support the per-cpu requests. This is done by
adding a per-cpu array for each constraint. This array holds the per-cpu QoS
value for each constraint. The intelligence behind the per-cpu is on the driver.
The framework just adds the request against the list held by the constraint
structure. Adding a request adds the request to the list of requests
against a constraint and also parses the array to see if this request superseeds
any existing QoS value for the cpus that this request has specified. The
workload of parsing the request is borne when updating the request.

- The driver that does an add request passes in the PM QoS request
  structure, can now pass in an additional request type that indicates if the
request is to be applied to all cores (default and existing behavior) or applies
to a subset of the cpus using a cpumask.

- To get the request value of a constraint back, you could use the
pm_qos_request() or its new cpu variants pm_qos_request_for_cpu() and
pm_qos_request_for_cpumask(). The _for_cpu() allows returns an s32 value without
locking.

- The next feature builds up on the per-cpu PM QoS feature to provide the
ability to allow a driver to tag a QoS request against an IRQ instead of a cpu.
Drivers may be concerned with an IRQ handling latency because of CPU low
power states, for example. When adding a request, they could specify the request
type to tag an IRQ and provide the IRQ numbers. When using tools like
irq-balancer, the IRQ affinity may jump from one cpu to another and in such a
case, the request needs to be modified correctly. irq/manage.c provides such
notification whenever the affinity changes. However, the current mechanism
allows for only one notification callback. 

- Change to the smp_affinity_notifications. Modify the exisiting
  mechanism of a single callback to support a list of requests. Drivers
  can register for change notifications.

- From PM QoS register for notification on behalf of a driver whenever
  a request with IRQ is specified. When the notification arrives, modify
  the cpu affinity of the QoS request to the cpus, that the IRQ is 
affine to.

- Remarks
I do not have the cpuidle governor changes here at this point. Also, there is
no change to userspace at this point, i.e, userspace cannot specify a QoS
request against a cpu or specify an IRQ to tag this request against.

Thanks,
Lina

Lina Iyer (4):
  QoS: Modify data structures and function arguments for scalability.
  QoS: Enhance framework to support per-cpu PM QoS request
  irq: Allow multiple clients to register for irq affinity notification
  QoS: Enable PM QoS requests to apply only on smp_affinity of an IRQ

 Documentation/power/pm_qos_interface.txt |  18 +++
 drivers/base/power/qos.c |  14 +--
 drivers/infiniband/hw/qib/qib_iba7322.c  |   4 +-
 include/linux/interrupt.h|  12 +-
 include/linux/irqdesc.h  |   6 +-
 include/linux/pm_qos.h   |  25 +++-
 kernel/irq/irqdesc.c |   1 +
 kernel/irq/manage.c  |  85 +-
 kernel/power/qos.c   | 191 ++-
 lib/cpu_rmap.c   |   2 +-
 10 files changed, 305 insertions(+), 53 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 1/4] QoS: Modify data structures and function arguments for scalability.

2014-08-27 Thread Lina Iyer
From: Praveen Chidambaram pchid...@codeaurora.org

QoS add requests uses a handle to the priority list that is used
internally to save the request, but this does not extend well. Also,
dev_pm_qos structure definition seems to use a list object directly.
The 'derivative' relationship seems to be broken.

Use pm_qos_request objects instead of passing around the protected
priority list object.

Signed-off-by: Praveen Chidambaram pchid...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org

diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 36b9eb4..67a66b1 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -143,7 +143,7 @@ static int apply_constraint(struct dev_pm_qos_request *req,
switch(req-type) {
case DEV_PM_QOS_RESUME_LATENCY:
ret = pm_qos_update_target(qos-resume_latency,
-  req-data.pnode, action, value);
+  req-data.lat, action, value);
if (ret) {
value = pm_qos_read_value(qos-resume_latency);
blocking_notifier_call_chain(dev_pm_notifiers,
@@ -153,7 +153,7 @@ static int apply_constraint(struct dev_pm_qos_request *req,
break;
case DEV_PM_QOS_LATENCY_TOLERANCE:
ret = pm_qos_update_target(qos-latency_tolerance,
-  req-data.pnode, action, value);
+  req-data.lat, action, value);
if (ret) {
value = pm_qos_read_value(qos-latency_tolerance);
req-dev-power.set_latency_tolerance(req-dev, value);
@@ -254,7 +254,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
 
/* Flush the constraints lists for the device. */
c = qos-resume_latency;
-   plist_for_each_entry_safe(req, tmp, c-list, data.pnode) {
+   plist_for_each_entry_safe(req, tmp, c-list, data.lat.node) {
/*
 * Update constraints list and call the notification
 * callbacks if needed
@@ -263,7 +263,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
memset(req, 0, sizeof(*req));
}
c = qos-latency_tolerance;
-   plist_for_each_entry_safe(req, tmp, c-list, data.pnode) {
+   plist_for_each_entry_safe(req, tmp, c-list, data.lat.node) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
@@ -378,7 +378,7 @@ static int __dev_pm_qos_update_request(struct 
dev_pm_qos_request *req,
switch(req-type) {
case DEV_PM_QOS_RESUME_LATENCY:
case DEV_PM_QOS_LATENCY_TOLERANCE:
-   curr_value = req-data.pnode.prio;
+   curr_value = req-data.lat.node.prio;
break;
case DEV_PM_QOS_FLAGS:
curr_value = req-data.flr.flags;
@@ -831,8 +831,8 @@ s32 dev_pm_qos_get_user_latency_tolerance(struct device 
*dev)
mutex_lock(dev_pm_qos_mtx);
ret = IS_ERR_OR_NULL(dev-power.qos)
|| !dev-power.qos-latency_tolerance_req ?
-   PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
-   dev-power.qos-latency_tolerance_req-data.pnode.prio;
+   PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
+   dev-power.qos-latency_tolerance_req-data.lat.node.prio;
mutex_unlock(dev_pm_qos_mtx);
return ret;
 }
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 9ab4bf7..e1b763d 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -60,7 +60,7 @@ enum dev_pm_qos_req_type {
 struct dev_pm_qos_request {
enum dev_pm_qos_req_type type;
union {
-   struct plist_node pnode;
+   struct pm_qos_request lat;
struct pm_qos_flags_request flr;
} data;
struct device *dev;
@@ -112,7 +112,8 @@ static inline int dev_pm_qos_request_active(struct 
dev_pm_qos_request *req)
return req-dev != NULL;
 }
 
-int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
+int pm_qos_update_target(struct pm_qos_constraints *c,
+struct pm_qos_request *req,
 enum pm_qos_req_action action, int value);
 bool pm_qos_update_flags(struct pm_qos_flags *pqf,
 struct pm_qos_flags_request *req,
@@ -210,7 +211,7 @@ int dev_pm_qos_update_user_latency_tolerance(struct device 
*dev, s32 val);
 
 static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
 {
-   return dev-power.qos-resume_latency_req-data.pnode.prio;
+   return dev-power.qos-resume_latency_req-data.lat.node.prio;
 }
 
 static inline s32 dev_pm_qos_requested_flags(struct device *dev)
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 884b770..d0b9c0f 100644
--- a/kernel/power/qos.c

Re: [PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-09-02 Thread Lina Iyer

On Wed, Aug 27 2014 at 14:56 -0600, Thomas Gleixner wrote:

On Wed, 27 Aug 2014, Lina Iyer wrote:


PM QoS and other idle frameworks can do a better job of addressing power
and performance requirements for a cpu, knowing the IRQs that are
affine to that cpu. If a performance request is placed against serving
the IRQ faster and if the IRQ is affine to a set of cpus, then setting
the performance requirements only on those cpus help save power on the
rest of the cpus. PM QoS framework is one such framework interested in
knowing the smp_affinity of an IRQ and the change notificiation in this
regard. QoS requests for the CPU_DMA_LATENCY constraint currently apply
to all cpus, but when attached to an IRQ, can be applied only to the set
of cpus that IRQ's smp_affinity is set to. This allows other cpus to
enter deeper sleep states to save power. More than one framework/driver
can be interested in such information.


All you are describing is the fact, that there is only a single
notifier possible right now, but you completely miss to describe WHY
you need multiple ones.

The existing notifier was introduced to tell the driver that the irq
affinity has changed, so it can move its buffers to the proper NUMA
node. So if that driver gets this information then it can tell the PM
QoS code that its affinity changed so that stuff can react
accordingly, right?


With the new PM QoS changes, multiple drivers would now be interested in
knowing the smp_affinity changes of the same IRQ. PM QoS abstracts the
notifier in the framework, so individual drivers dont have to register
for notification themselves and handle affinity notifications. But PM
QoS needs to coexist with NUMA and other arch drivers that need to
modify based on their arch specific needs upon affinity change
notifications.
Modifying the IRQ notifications to list, benefits having a simpler
mechanism to notify all arch drivers and frameworks like PM QoS.



This is going nowhere unless you provide a proper usecase and
arguments why this is necessary. Handwaving and I want a pony
arguments are not sufficient.

Thanks,

tglx

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-09-25 Thread Lina Iyer

On Tue, Sep 02 2014 at 14:56 -0600, Thomas Gleixner wrote:

On Tue, 2 Sep 2014, Lina Iyer wrote:

On Wed, Aug 27 2014 at 14:56 -0600, Thomas Gleixner wrote:
 On Wed, 27 Aug 2014, Lina Iyer wrote:

 All you are describing is the fact, that there is only a single
 notifier possible right now, but you completely miss to describe WHY
 you need multiple ones.

 The existing notifier was introduced to tell the driver that the irq
 affinity has changed, so it can move its buffers to the proper NUMA
 node. So if that driver gets this information then it can tell the PM
 QoS code that its affinity changed so that stuff can react
 accordingly, right?

With the new PM QoS changes, multiple drivers would now be interested in
knowing the smp_affinity changes of the same IRQ. PM QoS abstracts the


Again, you fail to tell me WHY multiple drivers are interested and
which drivers are interested and what they do with that information.


notifier in the framework, so individual drivers dont have to register
for notification themselves and handle affinity notifications. But PM
QoS needs to coexist with NUMA and other arch drivers that need to
modify based on their arch specific needs upon affinity change
notifications.


Lots of unspecified blurb. What has NUMA to do with other arch
drivers? Are you actually understanding what this is all about?


Modifying the IRQ notifications to list, benefits having a simpler
mechanism to notify all arch drivers and frameworks like PM QoS.


Painting my bikeshed blue benefits all neighbours and institutions
like the Royal Navy, right?

Sorry about not being very clear in my responses.



Lina, this is leading nowhere. You just make completely unspecified
claims and try to push your solution to a not explained problem
through. That's not how it works, at least not with me.

So please sit down and write up a proper description of the problem
you are trying to solve.

All I can see from your postings so far is:

   1) You want to use the notification for PM QoS

   2) You run into conflicts with the existing notifiers

   3) You want to solve that conflict

Here is the premise of my patchset - 


When a cpuidle governor selects the idle state of the cpu, it uses
the PM QoS CPU_DMA_LATENCY constraint value in determining the
acceptable tolerance in exit latency of the cpu, before choosing the low
power state for the cpu. Drivers specify the PM QoS request for this
constraint, indicating their tolerance. The aggregated QoS request is
used in determining the state of each cpu.
Now, when drivers make a request, they usually have a device IRQ in
mind, which generally needs to be addressed within the stipulated time
after the interrupt fires. By default, the IRQs' have affinity towards
many cpus. However, when used with a IRQ balancer, that sets the
affinity only to a subset of the available cpus, it seems inefficient
that all cpus obey the QoS requirement in terms of power.
Say, when an USB driver specifies a 2 millisecond QoS constraint, it
prevents all the cpus in the SoC from entering any power down state,
which need more than 2 ms to be effective.  Thats a lot of leakage
current that could be saved. The IRQ in many instances would just
wake up cpu0, while other cpus remain in high leakage idle states. This
information is critical to the governor to determine the best idle state
it could allow the cpu to be in.

So the change here is to specify QoS requests against a subset of cpus,
which when aggregated, the idle governor can distill out the QoS
requirement only for that cpu. When requests are made with a set of cpus
as the intended target for the QoS value, the PM QoS framework
calculates the QoS value for each cpu. The governor can then be modified
to request the QoS CPU_DMA_LATENCY constraint on an individual cpu and
can choose the deepest idle state that would respect the requirement.

By default QoS requests do not have a preference for cpus and that is
the behavior with these patches too. Using the per-cpu PM QoS, the
drivers can now specify a set of cpus that need to obey the QoS
requests, if they know the cpus or they would specify an IRQ, if the
request is to avoid latency in handling the device IRQ. The driver is
not expected to handle the IRQ's smp_affinity changes and would be done
by the PM QoS framework on behalf of the driver. This is not enforced on
the driver that they need to specify an IRQ or a subset of cpus for
their request. If there is no IRQ or cpu preference, then PM QoS
defaults to applying the request for all cpus. I would expect many of
the existing drivers still want this behavior.

In the case a driver is aware that the QoS request to guarantee a
certain performance in handling the device IRQ, the request can be made
to track the IRQ. PM QoS registers for a smp_affinity change and does
the best judgement based on the affinity. The IRQ may still fire on any
of the cpus in the affinity mask which would make it comparable to the
existing QoS behavior and no power

Re: [PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-09-25 Thread Lina Iyer

Resending...
Hoping to retain the thread information, this time.

On Tue, Sep 02 2014 at 14:56 -0600, Thomas Gleixner wrote:

On Tue, 2 Sep 2014, Lina Iyer wrote:

On Wed, Aug 27 2014 at 14:56 -0600, Thomas Gleixner wrote:
 On Wed, 27 Aug 2014, Lina Iyer wrote:

 All you are describing is the fact, that there is only a single
 notifier possible right now, but you completely miss to describe WHY
 you need multiple ones.

 The existing notifier was introduced to tell the driver that the irq
 affinity has changed, so it can move its buffers to the proper NUMA
 node. So if that driver gets this information then it can tell the PM
 QoS code that its affinity changed so that stuff can react
 accordingly, right?

With the new PM QoS changes, multiple drivers would now be interested in
knowing the smp_affinity changes of the same IRQ. PM QoS abstracts the


Again, you fail to tell me WHY multiple drivers are interested and
which drivers are interested and what they do with that information.


notifier in the framework, so individual drivers dont have to register
for notification themselves and handle affinity notifications. But PM
QoS needs to coexist with NUMA and other arch drivers that need to
modify based on their arch specific needs upon affinity change
notifications.


Lots of unspecified blurb. What has NUMA to do with other arch
drivers? Are you actually understanding what this is all about?


Modifying the IRQ notifications to list, benefits having a simpler
mechanism to notify all arch drivers and frameworks like PM QoS.


Painting my bikeshed blue benefits all neighbours and institutions
like the Royal Navy, right?

Sorry about not being very clear in my responses.



Lina, this is leading nowhere. You just make completely unspecified
claims and try to push your solution to a not explained problem
through. That's not how it works, at least not with me.

So please sit down and write up a proper description of the problem
you are trying to solve.

All I can see from your postings so far is:

   1) You want to use the notification for PM QoS

   2) You run into conflicts with the existing notifiers

   3) You want to solve that conflict

Here is the premise of my patchset - 


When a cpuidle governor selects the idle state of the cpu, it uses
the PM QoS CPU_DMA_LATENCY constraint value in determining the
acceptable tolerance in exit latency of the cpu, before choosing the low
power state for the cpu. Drivers specify the PM QoS request for this
constraint, indicating their tolerance. The aggregated QoS request is
used in determining the state of each cpu.
Now, when drivers make a request, they usually have a device IRQ in
mind, which generally needs to be addressed within the stipulated time
after the interrupt fires. By default, the IRQs' have affinity towards
many cpus. However, when used with a IRQ balancer, that sets the
affinity only to a subset of the available cpus, it seems inefficient
that all cpus obey the QoS requirement in terms of power.
Say, when an USB driver specifies a 2 millisecond QoS constraint, it
prevents all the cpus in the SoC from entering any power down state,
which need more than 2 ms to be effective.  Thats a lot of leakage
current that could be saved. The IRQ in many instances would just
wake up cpu0, while other cpus remain in high leakage idle states. This
information is critical to the governor to determine the best idle state
it could allow the cpu to be in.

So the change here is to specify QoS requests against a subset of cpus,
which when aggregated, the idle governor can distill out the QoS
requirement only for that cpu. When requests are made with a set of cpus
as the intended target for the QoS value, the PM QoS framework
calculates the QoS value for each cpu. The governor can then be modified
to request the QoS CPU_DMA_LATENCY constraint on an individual cpu and
can choose the deepest idle state that would respect the requirement.

By default QoS requests do not have a preference for cpus and that is
the behavior with these patches too. Using the per-cpu PM QoS, the
drivers can now specify a set of cpus that need to obey the QoS
requests, if they know the cpus or they would specify an IRQ, if the
request is to avoid latency in handling the device IRQ. The driver is
not expected to handle the IRQ's smp_affinity changes and would be done
by the PM QoS framework on behalf of the driver. This is not enforced on
the driver that they need to specify an IRQ or a subset of cpus for
their request. If there is no IRQ or cpu preference, then PM QoS
defaults to applying the request for all cpus. I would expect many of
the existing drivers still want this behavior.

In the case a driver is aware that the QoS request to guarantee a
certain performance in handling the device IRQ, the request can be made
to track the IRQ. PM QoS registers for a smp_affinity change and does
the best judgement based on the affinity. The IRQ may still fire on any
of the cpus in the affinity mask which

Re: [PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-11-17 Thread Lina Iyer

Hi Thomas,

On Fri, Oct 17 2014 at 01:29 -0600, Thomas Gleixner wrote:

On Fri, 10 Oct 2014, Lina Iyer wrote:

On Wed, Oct 08 2014 at 09:03 -0600, Thomas Gleixner wrote:
 On Thu, 25 Sep 2014, Lina Iyer wrote:
   How would a general keep track of the targets of all interrupts in
   the system mechanism make use of this?
  Sorry, I do not understand your question.
  PM QoS is only interested in the IRQs specified in the QoS request. If
  there are no requests that need to be associated with an IRQ, then PM
  QoS will not register for an affinity change notification.

 Right, and I really hate the whole per irq notifier. It's a rats nest
 of life time issues and other problems.

 It also does not tell you whether an irq is disabled, reenabled or
 removed, which will change the qos constraints as well unless you
 plaster all drivers with updates to qos for those cases.

 So what about adding a qos field to irq_data itself, have a function
 to update it and let the irq core keep track of the per cpu irq
 relevant qos constraints and provide an evaluation function or a
 notifier for the PM/idle code?

If that isnt intrusive in the IRQ core, then we can make it work for PM
QoS. The issue that I am concerned is that, it might result in back and
forth between IRQ and PM QoS frameworks. If that doesnt happen, then we
are good with this approach.


I can't tell that upfront, but I think it's worth to explore it.


I was able to review the options and I attempted a few methods, but
off-loading the QoS onto the IRQ framework, made it quite complex to
manage it. QoS values for each of the four constraints and the
constraints could be one of 3 types - min, max or sum, makes it a whole
lot of mess handling it in IRQ code.

I was able to get QoS to be notified of IRQ affinity changes without
using notifiers, but, I still am yet to find a way to modify QoS
requests on enable/disable of IRQ.

I will send the RFC of the new patchset, would be interested in taking a
look and let me know what you think.

Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4/RFC 2/4] QoS: Enhance PM QoS framework to support per-cpu QoS request

2014-11-17 Thread Lina Iyer
QoS request can be better optimized if the request can be set only for
the required cpus and not all cpus. This helps save power on other
cores, while still guaranteeing the quality of service on the desired
cores.

Add a new enumeration to specify the PM QoS request type. The enums help
specify what is the intended target cpu of the request.

Enhance the QoS constraints data structures to support target value for
each core. Requests specify if the QoS is applicable to all cores
(default) or to a selective subset of the cores or to a core(s).

Idle and interested drivers can request a PM QoS value for a constraint
across all cpus, or a specific cpu or a set of cpus. Separate APIs have
been added to request for individual cpu or a cpumask.  The default
behaviour of PM QoS is maintained i.e, requests that do not specify a
type of the request will continue to be effected on all cores.

The userspace sysfs interface does not support setting cpumask of a PM
QoS request.

Signed-off-by: Lina Iyer lina.i...@linaro.org
Based on work by: Praveen Chidambaram pchid...@codeaurora.org
https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/kernel/power?h=LNX.LA.3.7
---
 Documentation/power/pm_qos_interface.txt |  16 
 include/linux/pm_qos.h   |  12 +++
 kernel/power/qos.c   | 130 ++-
 3 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/Documentation/power/pm_qos_interface.txt 
b/Documentation/power/pm_qos_interface.txt
index 129f7c0..7f7a774 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -43,6 +43,15 @@ registered notifiers are called only if the target value is 
now different.
 Clients of pm_qos need to save the returned handle for future use in other
 pm_qos API functions.
 
+The handle is a pm_qos_request object. By default the request object sets the
+request type to PM_QOS_REQ_ALL_CORES, in which case, the PM QoS request
+applies to all cores. However, the driver can also specify a request type to
+be either of
+PM_QOS_REQ_ALL_CORES,
+PM_QOS_REQ_AFFINE_CORES,
+
+Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES.
+
 void pm_qos_update_request(handle, new_target_value):
 Will update the list element pointed to by the handle with the new target value
 and recompute the new aggregated target, calling the notification tree if the
@@ -56,6 +65,13 @@ the request.
 int pm_qos_request(param_class):
 Returns the aggregated value for a given PM QoS class.
 
+int pm_qos_request_for_cpu(param_class, cpu):
+Returns the aggregated value for a given PM QoS class for the specified cpu.
+
+int pm_qos_request_for_cpumask(param_class, cpumask):
+Returns the aggregated value for a given PM QoS class for the specified
+cpumask.
+
 int pm_qos_request_active(handle):
 Returns if the request is still active, i.e. it has not been removed from a
 PM QoS class constraints list.
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index c4d859e..de9b04b 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -9,6 +9,7 @@
 #include linux/miscdevice.h
 #include linux/device.h
 #include linux/workqueue.h
+#include linux/cpumask.h
 
 enum {
PM_QOS_RESERVED = 0,
@@ -42,7 +43,15 @@ enum pm_qos_flags_status {
 #define PM_QOS_FLAG_NO_POWER_OFF   (1  0)
 #define PM_QOS_FLAG_REMOTE_WAKEUP  (1  1)
 
+enum pm_qos_req_type {
+   PM_QOS_REQ_ALL_CORES = 0,
+   PM_QOS_REQ_AFFINE_CORES,
+};
+
 struct pm_qos_request {
+   enum pm_qos_req_type type;
+   struct cpumask cpus_affine;
+   /* Internal structure members */
struct plist_node node;
int pm_qos_class;
struct delayed_work work; /* for pm_qos_update_request_timeout */
@@ -83,6 +92,7 @@ enum pm_qos_type {
 struct pm_qos_constraints {
struct plist_head list;
s32 target_value;   /* Do not change to 64 bit */
+   s32 __percpu *target_per_cpu;
s32 default_value;
s32 no_constraint_value;
enum pm_qos_type type;
@@ -130,6 +140,8 @@ void pm_qos_update_request_timeout(struct pm_qos_request 
*req,
 void pm_qos_remove_request(struct pm_qos_request *req);
 
 int pm_qos_request(int pm_qos_class);
+int pm_qos_request_for_cpu(int pm_qos_class, int cpu);
+int pm_qos_request_for_cpumask(int pm_qos_class, struct cpumask *mask);
 int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_request_active(struct pm_qos_request *req);
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 602f5cb..36b4414 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -41,6 +41,7 @@
 #include linux/platform_device.h
 #include linux/init.h
 #include linux/kernel.h
+#include linux/cpumask.h
 
 #include linux/uaccess.h
 #include linux/export.h
@@ -182,6 +183,49 @@ static inline void pm_qos_set_value(struct 
pm_qos_constraints *c

[PATCH v4/RFC 0/4] per-cpu PM QoS

2014-11-17 Thread Lina Iyer
PM QoS constraints like the CPU_DMA_LATENCY, when set, apply to all cpus. The
QoS guarantees performance, at the expense of power. There is an opportunity to
save power on the cpus, if a subset of cpus need not participate in honoring
the QoS request.

The patches do the following - 

- Add type member to the QoS request data structure. Drivers requesting PM
  QoS, can qualify the type of the QoS request. Request could be either of
  all-cpus (default) or a cpumask or the cpus associated by smp-affinity to a
  device IRQ.

- QoS requests can supply an cpumask or an IRQ.

- Each constraint has a per-cpu target variable, to hold the QoS value for the
  constraint.

- When updating the QoS constraint target value, update the per-cpu target
  value of the constraint.

- Export the IRQ smp-affinity information from the IRQ framework.

- When the IRQ smp-affinity changes, notify PM QoS framework, which would update
  the target value for each of the constraint affected by the change in the
  smp-affinity of the IRQ.

TODO:

- Update the QoS constraint, when the IRQ is enabled/disabled.

- The IRQ affinity is an expected affinity, but the actual affinity is
  architecture dependent. Explore possibility of optimizations.

- Update cpuidle to use the per-cpu PM QoS to query the QoS value of the cpus
  interested.

Thanks,
Lina

Lina Iyer (4):
  QoS: Modify data structures and function arguments for scalability.
  QoS: Enhance PM QoS framework to support per-cpu QoS request
  irq: Add irq_get_affinity() api
  QoS: Enable PM QoS requests to apply only on smp_affinity of an IRQ

 Documentation/power/pm_qos_interface.txt |  18 +++
 drivers/base/power/qos.c |  14 +--
 include/linux/interrupt.h|   8 ++
 include/linux/pm_qos.h   |  22 +++-
 kernel/irq/manage.c  |  21 
 kernel/power/qos.c   | 183 +--
 6 files changed, 249 insertions(+), 17 deletions(-)

-- 
2.1.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4/RFC 1/4] QoS: Modify data structures and function arguments for scalability.

2014-11-17 Thread Lina Iyer
From: Praveen Chidambaram pchid...@codeaurora.org

QoS add requests uses a handle to the priority list that is used
internally to save the request, but this does not extend well. Also,
dev_pm_qos structure definition seems to use a list object directly.
The 'derivative' relationship seems to be broken.

Use pm_qos_request objects instead of passing around the protected
priority list object.

Signed-off-by: Lina Iyer lina.i...@linaro.org
Acked-by: Kevin Hilman khil...@linaro.org
---
 drivers/base/power/qos.c | 14 +++---
 include/linux/pm_qos.h   |  7 ---
 kernel/power/qos.c   | 14 --
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 36b9eb4..67a66b1 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -143,7 +143,7 @@ static int apply_constraint(struct dev_pm_qos_request *req,
switch(req-type) {
case DEV_PM_QOS_RESUME_LATENCY:
ret = pm_qos_update_target(qos-resume_latency,
-  req-data.pnode, action, value);
+  req-data.lat, action, value);
if (ret) {
value = pm_qos_read_value(qos-resume_latency);
blocking_notifier_call_chain(dev_pm_notifiers,
@@ -153,7 +153,7 @@ static int apply_constraint(struct dev_pm_qos_request *req,
break;
case DEV_PM_QOS_LATENCY_TOLERANCE:
ret = pm_qos_update_target(qos-latency_tolerance,
-  req-data.pnode, action, value);
+  req-data.lat, action, value);
if (ret) {
value = pm_qos_read_value(qos-latency_tolerance);
req-dev-power.set_latency_tolerance(req-dev, value);
@@ -254,7 +254,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
 
/* Flush the constraints lists for the device. */
c = qos-resume_latency;
-   plist_for_each_entry_safe(req, tmp, c-list, data.pnode) {
+   plist_for_each_entry_safe(req, tmp, c-list, data.lat.node) {
/*
 * Update constraints list and call the notification
 * callbacks if needed
@@ -263,7 +263,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
memset(req, 0, sizeof(*req));
}
c = qos-latency_tolerance;
-   plist_for_each_entry_safe(req, tmp, c-list, data.pnode) {
+   plist_for_each_entry_safe(req, tmp, c-list, data.lat.node) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
@@ -378,7 +378,7 @@ static int __dev_pm_qos_update_request(struct 
dev_pm_qos_request *req,
switch(req-type) {
case DEV_PM_QOS_RESUME_LATENCY:
case DEV_PM_QOS_LATENCY_TOLERANCE:
-   curr_value = req-data.pnode.prio;
+   curr_value = req-data.lat.node.prio;
break;
case DEV_PM_QOS_FLAGS:
curr_value = req-data.flr.flags;
@@ -831,8 +831,8 @@ s32 dev_pm_qos_get_user_latency_tolerance(struct device 
*dev)
mutex_lock(dev_pm_qos_mtx);
ret = IS_ERR_OR_NULL(dev-power.qos)
|| !dev-power.qos-latency_tolerance_req ?
-   PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
-   dev-power.qos-latency_tolerance_req-data.pnode.prio;
+   PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
+   dev-power.qos-latency_tolerance_req-data.lat.node.prio;
mutex_unlock(dev_pm_qos_mtx);
return ret;
 }
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 636e828..c4d859e 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -62,7 +62,7 @@ enum dev_pm_qos_req_type {
 struct dev_pm_qos_request {
enum dev_pm_qos_req_type type;
union {
-   struct plist_node pnode;
+   struct pm_qos_request lat;
struct pm_qos_flags_request flr;
} data;
struct device *dev;
@@ -115,7 +115,8 @@ static inline int dev_pm_qos_request_active(struct 
dev_pm_qos_request *req)
return req-dev != NULL;
 }
 
-int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
+int pm_qos_update_target(struct pm_qos_constraints *c,
+struct pm_qos_request *req,
 enum pm_qos_req_action action, int value);
 bool pm_qos_update_flags(struct pm_qos_flags *pqf,
 struct pm_qos_flags_request *req,
@@ -213,7 +214,7 @@ int dev_pm_qos_update_user_latency_tolerance(struct device 
*dev, s32 val);
 
 static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
 {
-   return dev-power.qos-resume_latency_req-data.pnode.prio;
+   return dev-power.qos-resume_latency_req-data.lat.node.prio

[PATCH v4/RFC 4/4] QoS: Enable PM QoS requests to apply only on smp_affinity of an IRQ

2014-11-17 Thread Lina Iyer
QoS requests that need to track an IRQ can be set to apply only on the
cpus to which the IRQ's smp_affinity attribute is set to. The PM QoS
framework will automatically track IRQ migration between the cores. The
QoS is updated to be applied only to the core(s) that the IRQ has been
migrated to.

The userspace sysfs interface does not support IRQ affinity.

Signed-off-by: Lina Iyer lina.i...@linaro.org
Based on work by: Praveen Chidambaram pchid...@codeaurora.org
---
 Documentation/power/pm_qos_interface.txt |  4 +++-
 include/linux/pm_qos.h   |  3 +++
 kernel/irq/manage.c  |  3 +++
 kernel/power/qos.c   | 41 +++-
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/Documentation/power/pm_qos_interface.txt 
b/Documentation/power/pm_qos_interface.txt
index 7f7a774..73bfa16 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -49,8 +49,10 @@ applies to all cores. However, the driver can also specify a 
request type to
 be either of
 PM_QOS_REQ_ALL_CORES,
 PM_QOS_REQ_AFFINE_CORES,
+PM_QOS_REQ_AFFINE_IRQ,
 
-Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES.
+Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES and specify
+the IRQ number with PM_QOS_REQ_AFFINE_IRQ.
 
 void pm_qos_update_request(handle, new_target_value):
 Will update the list element pointed to by the handle with the new target value
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index de9b04b..e0b80af 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -46,11 +46,13 @@ enum pm_qos_flags_status {
 enum pm_qos_req_type {
PM_QOS_REQ_ALL_CORES = 0,
PM_QOS_REQ_AFFINE_CORES,
+   PM_QOS_REQ_AFFINE_IRQ,
 };
 
 struct pm_qos_request {
enum pm_qos_req_type type;
struct cpumask cpus_affine;
+   uint32_t irq;
/* Internal structure members */
struct plist_node node;
int pm_qos_class;
@@ -146,6 +148,7 @@ int pm_qos_add_notifier(int pm_qos_class, struct 
notifier_block *notifier);
 int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_request_active(struct pm_qos_request *req);
 s32 pm_qos_read_value(struct pm_qos_constraints *c);
+void pm_qos_irq_affinity_change(u32 irq, const struct cpumask *mask);
 
 #ifdef CONFIG_PM
 enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2d17098..8790f71 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -18,6 +18,7 @@
 #include linux/sched.h
 #include linux/sched/rt.h
 #include linux/task_work.h
+#include linux/pm_qos.h
 
 #include internals.h
 
@@ -209,6 +210,8 @@ int irq_set_affinity_locked(struct irq_data *data, const 
struct cpumask *mask,
irq_copy_pending(desc, mask);
}
 
+   pm_qos_irq_affinity_change(data-irq, mask);
+
if (desc-affinity_notify) {
kref_get(desc-affinity_notify-kref);
schedule_work(desc-affinity_notify-work);
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 36b4414..43de784 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -42,6 +42,7 @@
 #include linux/init.h
 #include linux/kernel.h
 #include linux/cpumask.h
+#include linux/interrupt.h
 
 #include linux/uaccess.h
 #include linux/export.h
@@ -460,6 +461,39 @@ static void pm_qos_work_fn(struct work_struct *work)
__pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
 }
 
+void pm_qos_irq_affinity_change(u32 irq, const struct cpumask *mask)
+{
+   struct pm_qos_constraints *c;
+   unsigned long flags;
+   struct pm_qos_request *req;
+   s32 curr_value;
+   int i;
+   bool needs_update;
+
+   for (i = PM_QOS_CPU_DMA_LATENCY; i  PM_QOS_NUM_CLASSES; i++) {
+   c = pm_qos_array[i]-constraints;
+   if (plist_head_empty(c-list))
+   continue;
+   needs_update = false;
+   spin_lock_irqsave(pm_qos_lock, flags);
+   plist_for_each_entry(req, c-list, node) {
+   if (req-irq == irq) {
+   cpumask_copy(req-cpus_affine, mask);
+   needs_update = true;
+   }
+   }
+   if (needs_update) {
+   pm_qos_set_value_for_cpus(c);
+   curr_value = pm_qos_get_value(c);
+   }
+   spin_unlock_irqrestore(pm_qos_lock, flags);
+   if (needs_update  c-notifiers)
+   blocking_notifier_call_chain(c-notifiers,
+   (unsigned long)curr_value,
+   NULL);
+   }
+}
+
 /**
  * pm_qos_add_request - inserts new qos request into the list
  * @req: pointer to a preallocated

[PATCH v4/RFC 3/4] irq: Add irq_get_affinity() api

2014-11-17 Thread Lina Iyer
Export irq_get_affinity API for drivers to read the smp affinity of an
IRQ safely.

Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 include/linux/interrupt.h |  8 
 kernel/irq/manage.c   | 18 ++
 2 files changed, 26 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 69517a2..fff619c 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -260,6 +260,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const 
struct cpumask *m);
 extern int
 irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify 
*notify);
 
+extern int irq_get_affinity(unsigned int irq, struct cpumask *mask);
+
 #else /* CONFIG_SMP */
 
 static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)
@@ -290,6 +292,12 @@ irq_set_affinity_notifier(unsigned int irq, struct 
irq_affinity_notify *notify)
 {
return 0;
 }
+
+static inline int irq_get_affinity(unsigned int irq, struct cpumask *mask)
+{
+   return -EINVAL;
+}
+
 #endif /* CONFIG_SMP */
 
 /*
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0a9104b..2d17098 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -246,6 +246,24 @@ int irq_set_affinity_hint(unsigned int irq, const struct 
cpumask *m)
 }
 EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
 
+int irq_get_affinity(unsigned int irq, struct cpumask *mask)
+{
+   struct irq_desc *desc = irq_to_desc(irq);
+   unsigned long flags;
+
+   if (!mask)
+   return -EINVAL;
+
+   raw_spin_lock_irqsave(desc-lock, flags);
+   if (!irqd_irq_disabled(desc-irq_data))
+   cpumask_copy(mask, desc-irq_data.affinity);
+   else
+   cpumask_clear(mask);
+   raw_spin_unlock_irqrestore(desc-lock, flags);
+
+   return 0;
+}
+
 static void irq_affinity_notify(struct work_struct *work)
 {
struct irq_affinity_notify *notify =
-- 
2.1.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 3/4] irq: Allow multiple clients to register for irq affinity notification

2014-10-10 Thread Lina Iyer

On Wed, Oct 08 2014 at 09:03 -0600, Thomas Gleixner wrote:

On Thu, 25 Sep 2014, Lina Iyer wrote:

 How would a general keep track of the targets of all interrupts in
 the system mechanism make use of this?
Sorry, I do not understand your question.
PM QoS is only interested in the IRQs specified in the QoS request. If
there are no requests that need to be associated with an IRQ, then PM
QoS will not register for an affinity change notification.


Right, and I really hate the whole per irq notifier. It's a rats nest
of life time issues and other problems.

It also does not tell you whether an irq is disabled, reenabled or
removed, which will change the qos constraints as well unless you
plaster all drivers with updates to qos for those cases.

So what about adding a qos field to irq_data itself, have a function
to update it and let the irq core keep track of the per cpu irq
relevant qos constraints and provide an evaluation function or a
notifier for the PM/idle code?

If that isnt intrusive in the IRQ core, then we can make it work for PM
QoS. The issue that I am concerned is that, it might result in back and
forth between IRQ and PM QoS frameworks. If that doesnt happen, then we
are good with this approach.


That's going to need some serious thought as well, but it should avoid
most of the nasty notifier and lifetime issue which the per irq
notifiers provide.

Sure. I will look into this.


Thoughts?


Thank you.

Lina






--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v1 4/7] thermal: introduce the Power Allocator governor

2015-02-02 Thread Lina Iyer

On Wed, Jan 28 2015 at 14:42 -0700, Javi Merino wrote:

The power allocator governor is a thermal governor that controls system
and device power allocation to control temperature.  Conceptually, the
implementation divides the sustainable power of a thermal zone among
all the heat sources in that zone.

This governor relies on power actors, entities that represent heat
sources.  They can report current and maximum power consumption and
can set a given maximum power consumption, usually via a cooling
device.

The governor uses a Proportional Integral Derivative (PID) controller
driven by the temperature of the thermal zone.  The output of the
controller is a power budget that is then allocated to each power
actor that can have bearing on the temperature we are trying to
control.  It decides how much power to give each cooling device based
on the performance they are requesting.  The PID controller ensures
that the total power budget does not exceed the control temperature.

Cc: Zhang Rui rui.zh...@intel.com
Cc: Eduardo Valentin edubez...@gmail.com
Signed-off-by: Punit Agrawal punit.agra...@arm.com
Signed-off-by: Javi Merino javi.mer...@arm.com
---
Documentation/thermal/power_allocator.txt | 241 +++
drivers/thermal/Kconfig   |  15 +
drivers/thermal/Makefile  |   1 +
drivers/thermal/power_allocator.c | 478 ++
drivers/thermal/thermal_core.c|   9 +-
drivers/thermal/thermal_core.h|   8 +
include/linux/thermal.h   |  37 ++-
7 files changed, 782 insertions(+), 7 deletions(-)
create mode 100644 Documentation/thermal/power_allocator.txt
create mode 100644 drivers/thermal/power_allocator.c

diff --git a/Documentation/thermal/power_allocator.txt 
b/Documentation/thermal/power_allocator.txt
new file mode 100644
index ..c9604e76c544
--- /dev/null
+++ b/Documentation/thermal/power_allocator.txt
@@ -0,0 +1,241 @@
+Power allocator governor tunables
+=
+
+Trip points
+---
+
+The governor requires the following two passive trip points:
+
+1.  switch on trip point: temperature above which the governor
+control loop starts operating.
+2.  desired temperature trip point: it should be higher than the
+switch on trip point.  This the target temperature the governor
+is controlling for.
+
+PID Controller
+--
+
+The power allocator governor implements a
+Proportional-Integral-Derivative controller (PID controller) with
+temperature as the control input and power as the controlled output:
+
+P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
+
+where
+e = desired_temperature - current_temperature
+err_integral is the sum of previous errors
+diff_err = e - previous_error
+
+It is similar to the one depicted below:
+
+  k_d
+   |
+current_temp   |
+ | v
+ |+--+   +---+
+ | +-| diff_err |--| X |--+
+ | |  +--+   +---+  |
+ | ||  tdpactor
+ | |  k_i   |   |  
get_requested_power()
+ | |   ||   || |
+ | |   ||   || | ...
+ v |   vv   vv v
+   +---+   |  +---+  +---++---+   +---+   +--+
+   | S |---+-| sum e |-| X |---| S |--| S |--|power |
+   +---+   |  +---+  +---++---+   +---+   |allocation|
+ ^ |^ +--+
+ | ||| |
+ | |+---+   || |
+ | +---| X |---+v v
+ |  +---+   granted performance
+desired_temperature   ^
+  |
+  |
+  k_po/k_pu
+
+Sustainable power
+-
+
+An estimate of the sustainable dissipatable power (in mW) should be
+provided while registering the thermal zone.  This estimates the
+sustained power that can be dissipated at the desired control
+temperature.  This is the maximum sustained power for allocation at
+the desired maximum temperature.  The actual sustained power can vary
+for a number of reasons.  The closed loop controller will take care of
+variations such as environmental conditions, and some factors related
+to the speed-grade of the silicon.  `sustainable_power` is therefore
+simply an estimate, and may be tuned to affect the aggressiveness of
+the thermal ramp. For reference, the 

Re: [PATCH v1 4/7] thermal: introduce the Power Allocator governor

2015-02-03 Thread Lina Iyer

On Tue, Feb 03 2015 at 08:30 -0700, Eduardo Valentin wrote:

On Tue, Feb 03, 2015 at 01:03:37PM +, Javi Merino wrote:

On Mon, Feb 02, 2015 at 11:51:20PM +, Lina Iyer wrote:
 On Wed, Jan 28 2015 at 14:42 -0700, Javi Merino wrote:
 The power allocator governor is a thermal governor that controls system
 and device power allocation to control temperature.  Conceptually, the
 implementation divides the sustainable power of a thermal zone among
 all the heat sources in that zone.
 
 This governor relies on power actors, entities that represent heat
 sources.  They can report current and maximum power consumption and
 can set a given maximum power consumption, usually via a cooling
 device.
 
 The governor uses a Proportional Integral Derivative (PID) controller
 driven by the temperature of the thermal zone.  The output of the
 controller is a power budget that is then allocated to each power
 actor that can have bearing on the temperature we are trying to
 control.  It decides how much power to give each cooling device based
 on the performance they are requesting.  The PID controller ensures
 that the total power budget does not exceed the control temperature.
 
 Cc: Zhang Rui rui.zh...@intel.com
 Cc: Eduardo Valentin edubez...@gmail.com
 Signed-off-by: Punit Agrawal punit.agra...@arm.com
 Signed-off-by: Javi Merino javi.mer...@arm.com
 ---
  Documentation/thermal/power_allocator.txt | 241 +++
  drivers/thermal/Kconfig   |  15 +
  drivers/thermal/Makefile  |   1 +
  drivers/thermal/power_allocator.c | 478 
++
  drivers/thermal/thermal_core.c|   9 +-
  drivers/thermal/thermal_core.h|   8 +
  include/linux/thermal.h   |  37 ++-
  7 files changed, 782 insertions(+), 7 deletions(-)
  create mode 100644 Documentation/thermal/power_allocator.txt
  create mode 100644 drivers/thermal/power_allocator.c
 
[...]
 diff --git a/drivers/thermal/power_allocator.c 
b/drivers/thermal/power_allocator.c
 new file mode 100644
 index ..c929143aee67
 --- /dev/null
 +++ b/drivers/thermal/power_allocator.c
 @@ -0,0 +1,478 @@
 +/*
 + * A power allocator to manage temperature
 + *
 + * Copyright (C) 2014 ARM Ltd.
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License version 2 as
 + * published by the Free Software Foundation.
 + *
 + * This program is distributed as is WITHOUT ANY WARRANTY of any
 + * kind, whether express or implied; without even the implied warranty
 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 + * GNU General Public License for more details.
 + */
 +
 +#define pr_fmt(fmt) Power allocator:  fmt
 +
 +#include linux/rculist.h
 +#include linux/slab.h
 +#include linux/thermal.h
 +
 +#include thermal_core.h
 +
 +#define FRAC_BITS 10
 +#define int_to_frac(x) ((x)  FRAC_BITS)
 +#define frac_to_int(x) ((x)  FRAC_BITS)
 +
 +/**
 + * mul_frac() - multiply two fixed-point numbers
 + * @x:first multiplicand
 + * @y:second multiplicand
 + *
 + * Return: the result of multiplying two fixed-point numbers.  The
 + * result is also a fixed-point number.
 + */
 +static inline s64 mul_frac(s64 x, s64 y)
 +{
 +  return (x * y)  FRAC_BITS;
 +}
 +
 +enum power_allocator_trip_levels {
 +  TRIP_SWITCH_ON = 0, /* Switch on PID controller */
 +  TRIP_MAX_DESIRED_TEMPERATURE, /* Temperature we are controlling for */
 +
 +  THERMAL_TRIP_NUM,
 +};

 This has to be exported for tz's to respond to the request. See below.

 +
 +/**
 + * struct power_allocator_params - parameters for the power allocator 
governor
 + * @err_integral: accumulated error in the PID controller.
 + * @prev_err: error in the previous iteration of the PID controller.
 + *Used to calculate the derivative term.
 + */
 +struct power_allocator_params {
 +  s64 err_integral;
 +  s32 prev_err;
 +};
 +
 +/**
 + * pid_controller() - PID controller
 + * @tz:   thermal zone we are operating in
 + * @current_temp: the current temperature in millicelsius
 + * @control_temp: the target temperature in millicelsius
 + * @max_allocatable_power:maximum allocatable power for this thermal 
zone
 + *
 + * This PID controller increases the available power budget so that the
 + * temperature of the thermal zone gets as close as possible to
 + * @control_temp and limits the power if it exceeds it.  k_po is the
 + * proportional term when we are overshooting, k_pu is the
 + * proportional term when we are undershooting.  integral_cutoff is a
 + * threshold below which we stop accumulating the error.  The
 + * accumulated error is only valid if the requested power will make
 + * the system warmer.  If the system is mostly idle, there's no point
 + * in accumulating positive error.
 + *
 + * Return: The power budget for the next period.
 + */
 +static u32 pid_controller(struct

Re: [PATCH V2 2/2] spmi: pmic_arb: add support for hw version 2

2015-02-03 Thread Lina Iyer

On Tue, Feb 03 2015 at 02:59 -0700, Stanimir Varbanov wrote:

Hi Gilad,

Thanks for the patch.

On 01/31/2015 02:46 AM, Gilad Avidov wrote:

Qualcomm PMIC Arbiter version-2 changes from version-1 are:

- Some different register offsets.
- New channel register space, one per PMIC peripheral (ppid).
  All tx traffic uses these channels.
- New observer register space. All rx trafic uses this space.
- Different command format for spmi command registers.

Signed-off-by: Gilad Avidov gavi...@codeaurora.org
Acked-by: Sagar Dharia sdha...@codeaurora.org
---
 .../bindings/spmi/qcom,spmi-pmic-arb.txt   |   6 +-
 drivers/spmi/spmi-pmic-arb.c   | 310 +
 2 files changed, 260 insertions(+), 56 deletions(-)

diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt 
b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
index 715d099..e16b9b5 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
@@ -1,6 +1,6 @@
 Qualcomm SPMI Controller (PMIC Arbiter)

-The SPMI PMIC Arbiter is found on the Snapdragon 800 Series.  It is an SPMI
+The SPMI PMIC Arbiter is found on Snapdragon chipsets.  It is an SPMI
 controller with wrapping arbitration logic to allow for multiple on-chip
 devices to control a single SPMI master.

@@ -19,6 +19,10 @@ Required properties:
  core - core registers
  intr - interrupt controller registers
  cnfg - configuration registers
+   Registers used only for V2 PMIC Arbiter:
+ chnls  - tx-channel per virtual slave registers.
+ obsrvr - rx-channel (called observer) per virtual slave registers.
+
 - reg : address + size pairs describing the PMIC arb register sets; order must
 correspond with the order of entries in reg-names
 - #address-cells : must be set to 2
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 20559ab..818b2cf 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.


run checkpatch, there are tons of errors like white spaces and DOS line
ending.


I dont see any DOS line endings with these patches. I believe the
checkpatch warnings also are false positives.

Thanks,
Lina




  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,22 +25,18 @@

 /* PMIC Arbiter configuration registers */
 #define PMIC_ARB_VERSION   0x
+#define PMIC_ARB_VERSION_V2_MIN(0x2001)
 #define PMIC_ARB_INT_EN0x0004

-/* PMIC Arbiter channel registers */
-#define PMIC_ARB_CMD(N)(0x0800 + (0x80 * (N)))
-#define PMIC_ARB_CONFIG(N) (0x0804 + (0x80 * (N)))
-#define PMIC_ARB_STATUS(N) (0x0808 + (0x80 * (N)))
-#define PMIC_ARB_WDATA0(N) (0x0810 + (0x80 * (N)))
-#define PMIC_ARB_WDATA1(N) (0x0814 + (0x80 * (N)))
-#define PMIC_ARB_RDATA0(N) (0x0818 + (0x80 * (N)))
-#define PMIC_ARB_RDATA1(N) (0x081C + (0x80 * (N)))
-
-/* Interrupt Controller */
-#define SPMI_PIC_OWNER_ACC_STATUS(M, N)(0x + ((32 * (M)) + (4 * 
(N
-#define SPMI_PIC_ACC_ENABLE(N) (0x0200 + (4 * (N)))
-#define SPMI_PIC_IRQ_STATUS(N) (0x0600 + (4 * (N)))
-#define SPMI_PIC_IRQ_CLEAR(N)  (0x0A00 + (4 * (N)))
+/* PMIC Arbiter channel registers offsets */
+#define PMIC_ARB_CMD   (0x00)


no need braces here and below


+#define PMIC_ARB_CONFIG(0x04)
+#define PMIC_ARB_STATUS(0x08)
+#define PMIC_ARB_WDATA0(0x10)
+#define PMIC_ARB_WDATA1(0x14)
+#define PMIC_ARB_RDATA0(0x18)
+#define PMIC_ARB_RDATA1(0x1C)
+#define PMIC_ARB_REG_CHNL(N)   (0x800 + 0x4 * (N))

 /* Mapping Table */
 #define SPMI_MAPPING_TABLE_REG(N)  (0x0B00 + (4 * (N)))
@@ -52,6 +48,7 @@

 #define SPMI_MAPPING_TABLE_LEN 255
 #define SPMI_MAPPING_TABLE_TREE_DEPTH  16  /* Maximum of 16-bits */
+#define PPID_TO_CHAN_TABLE_SZ  BIT(12) /* PPID is 12bit chan is 1byte*/

 /* Ownership Table */
 #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N)))
@@ -88,6 +85,7 @@ enum pmic_arb_cmd_op_code {

 /* Maximum number of support PMIC peripherals */
 #define PMIC_ARB_MAX_PERIPHS   256
+#define PMIC_ARB_MAX_CHNL  128
 #define PMIC_ARB_PERIPH_ID_VALID   (1  15)
 #define PMIC_ARB_TIMEOUT_US100
 #define PMIC_ARB_MAX_TRANS_BYTES   (8)
@@ -98,14 +96,17 @@ enum pmic_arb_cmd_op_code {
 /* interrupt enable bit */
 #define SPMI_PIC_ACC_ENABLE_BITBIT(0)

+struct pmic_arb_ver_ops;
+
 /**
  * 

Re: [PATCH v1 4/7] thermal: introduce the Power Allocator governor

2015-02-04 Thread Lina Iyer

On Tue, Feb 03 2015 at 12:20 -0700, Eduardo Valentin wrote:

On Tue, Feb 03, 2015 at 10:32:11AM -0700, Lina Iyer wrote:

big cut



Well, I am not convinced drivers really need to be aware of these trip
types. Which kind of drivers are we talking? Thermal zone drivers?
cooling device drivers?

I am sorry, I am missing the point here. The Tz driver is requested to
return the type of an enum and if the enum is not shared, then how is
the driver expected to know what to return.


Yeah, however, the only requirement I see for this governor is to have
two passive trip points.


I understand, but the thermal zone may have multiple trip points that
are passive. How would the thermal zone indentify which trip point is of
interest to this particular governor.


From what I see, every governor can define its number/type of trip

requirements and the TZ can define any number of trip points. I dont see
how I can write a TZ driver tha would work with a  governor in the
future that may expect more than 2 passive trip points.



Lina, do you have an existing driver (it can be yet to be posted) that
would required using these types? To my understanding, these are simply
for the governor internal control, drivers do not really need to understand
the difference from one to another.

I am currently prototyping Javi's patches on QCOM existing solution. So its all 
WIP.


I see.



The purpose of the .bind_to_tz callback is exactly to verify if the
driver has added the required info into the thermal zone. Including the
trip setup.

I may be completely off-base here and my understanding of trips is
questionable. But it seems like even with this callback, the driver
expected to know what the particular governor defines and needs from the
TZ.  The definitions may overlap and may mean different things in
different governros. To me a TZ driver should not care what the
governors are, but define some common parameters that any governor can
work with. Am I making sense here?



And that's is what I want to keep across the framework. Thermal zone
driver should not really be aware of governor details. Ideally, the
driver should provide a thermal zone that can be usable by different
governors. That is the ideal setup.


Right, but if the governors have no common enums, the driver would not know how
many trip points to implement.



If we allow this new governor to have its own trip types, we will be
segregating thermal zones. And that should be avoid if possible.





Besides, the existing exposed trip types are sufficient, given that this
series is in a working state. Unless we have a valid use case to change
/ add trip types and expose them to driver, I would prefer to keep this
simple.

Side note, drivers/thermal/thermal_core.h has symbols that are not
exported. As drivers can be built as separated modules from thermal
core, I would not recommend include things in that header. The symbols
that are EXPORT_SYMBOL'ed are in thermal.h under include directory.


 Cheers,
 Javi

  I dont think anymore, this should be a enum thermal_trip_type, but it has 
to be
  generic across governors.
 
 
  Thanks,
  Lina





--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] hwspinlock: qcom: Add support for Qualcomm HW Mutex block

2015-03-18 Thread Lina Iyer

On Wed, Mar 18 2015 at 09:56 -0600, Bjorn Andersson wrote:

On Thu 12 Mar 12:31 PDT 2015, Lina Iyer wrote:


On Fri, Feb 27 2015 at 15:30 -0700, Bjorn Andersson wrote:
Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
SoCs.

Based on initial effort by Kumar Gala ga...@codeaurora.org

Signed-off-by: Bjorn Andersson bjorn.anders...@sonymobile.com
---


[...]

+#include hwspinlock_internal.h
+
+#define QCOM_MUTEX_APPS_PROC_ID1
Hi Bjorn,

Not all locks use 1 to indicate its locked. For example lock index 7 is
used by cpuidle driver between HLOS and SCM. It uses a write value of
(128 + smp_processor_id()) to lock.



In other words, it's a magic number that will make sure that not more
than one cpu enters TZ sleep code at a time.


Right, its a magic number of sorts.


A cpu acquires the remote spin lock, and calls into SCM to terminate the
power down sequence while passing the state of the L2. The lock help
guarantee the last core to hold the spinlock to have the most up to date
value for the L2 flush flag.



Yeah, I remember having to dig out the deadlock related to the
introduction of that logic on my side (turned out to have an old TZ).

There's already mutual exclusion and reference counting within TZ to
make sure we're not turning off the caches unless this is the last core
going down.


Yes, there is. But the perception of the last core in Linux and the last
core going down in TZ may be incorrect. Say for example, two cpus are
going down from linux - cpu0  cpu1. cpu0 was the last core calling into
TZ from Linux and cpu1 had already done so. However, cpu1 started
handling an FIQ and therefore was blocked doing that while cpu0, went
through TZ. When each cpu calls into TZ, we provide the TZ with the L2
flush flag so as to allow TZ to also flush its secure lines before
powering the L2 down. The L2 flush flag that the cpu submits is its own
version of the system state. To get TZ to recognize the last valid l2
flush flag value from Linux, we need the hwmutex.


I presume that the reason behind the hwmutex logic is to make sure that
with multiple cores racing to sleep only one of them will flush the
caches in Linux and will be the last entering TZ. Can you confirm this?


Its more for passing the flush flag than flushing the cache itself per-se.


+#define QCOM_MUTEX_NUM_LOCKS   32

Also, talking to Jeff it seems like that out of the 32 locks defined
only 8 is accessible from Linux. So its unnecessary and probably
incorrect to assume that there are 32 locks available.



The hardware block have 32 locks and the decision regarding which locks
this particular Linux system is allowed to access is configuration.


Understood. But while the hardware may support it, it may be right for
Linux to be allowed to configure, giving a false sense of number of
locks.


Regards,
Bjorn

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] hwspinlock: qcom: Add support for Qualcomm HW Mutex block

2015-03-18 Thread Lina Iyer

On Wed, Mar 18 2015 at 10:12 -0600, Bjorn Andersson wrote:

On Thu 12 Mar 15:29 PDT 2015, Lina Iyer wrote:


On Fri, Feb 27 2015 at 15:30 -0700, Bjorn Andersson wrote:
Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
SoCs.

Based on initial effort by Kumar Gala ga...@codeaurora.org

Signed-off-by: Bjorn Andersson bjorn.anders...@sonymobile.com
+config HWSPINLOCK_QCOM
+   tristate Qualcomm Hardware Spinlock device

Any reason, why this is tristate and not a bool?


+   depends on ARCH_QCOM
+   select HWSPINLOCK

select MFD_SYSCON as well, perhaps?
We seem to be dependent on it.



Right, missed that. Thanks!

Will resend with that addition.

Regards,
Bjorn


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] Lock 7 is cpuidle specific, use non-generic value for locking

2015-03-13 Thread Lina Iyer

On Fri, Mar 13 2015 at 14:02 -0600, Andy Gross wrote:

On Thu, Mar 12, 2015 at 04:16:00PM -0600, Lina Iyer wrote:

snip


It looks like the remote side unlocks it too? It doesn't seem like this
will work with the framework very well. The framework has a kernel
spinlock attached to the hwspinlock so when we lock the hwspinlock we
also lock the kernel spinlock and we only release the kernel spinlock
when the kernel unlocks the hwspinlock. In this case it seems like
cpuidle wants to have it's own kernel spinlock and just use the trylock
loop part of __hwspin_lock_timeout() without taking any kernel side
locks. Plus it wants to write a specific value to the lock.

Right.
Just noticed that part of the hwspinlock. Yes SCM unlocks the
hwspinlock. So I cannot hold any lock in Linux. May need changes in the
hwspinlock framework. Seems like an additional flag in hwspinlock to not
lock any in the trylock path work work. Hmm


Or a specific EXPORT function for this one usecase which is unlike anyone elses
usage.


I think, this can be handled well within the QCOM driver. I will submit
a patch for it and we can discuss then later. For now, this will work
fine as is.

Lina



--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] Lock 7 is cpuidle specific, use non-generic value for locking

2015-03-12 Thread Lina Iyer

On Thu, Mar 12 2015 at 14:35 -0600, Stephen Boyd wrote:

On 03/12/15 12:38, Lina Iyer wrote:

---


sign off?


:) I was just hacking it to make it easier to understand. Sure.


 drivers/hwspinlock/qcom_hwspinlock.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/hwspinlock/qcom_hwspinlock.c 
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..7642524 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,23 @@

 #include hwspinlock_internal.h

-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS   32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET  128
+#define QCOM_CPUIDLE_LOCK  7
+#define QCOM_MUTEX_NUM_LOCKS   32

 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
struct regmap_field *field = lock-priv;
u32 lock_owner;
int ret;
+   u32 proc_id;

-   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   proc_id = hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+   QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id():


So we assume that the caller will always be the CPU that is locking the
lock? Also, do we assume that the remote side knows our CPU scheme here?
smp_processor_id() returns the logical CPU and not the physical CPU
number so hopefully the remote side doesn't care about logical CPU
numbers being written to the lock value.


The remote side (SCM) doesnt care the value written. We use 128+cpu to
be unique in Linux(128 is to make sure it doesnt clash with predefined
values used across by other processors.



Perhaps it would be better to have a way to tell the hwspinlock
framework what value we want written to the lock value.


That would be good, if there is value in that for other platforms, I
will gladly make the change.

Thoughts?


+   QCOM_MUTEX_APPS_PROC_ID;
+
+   ret = regmap_field_write(field, proc_id);
if (ret)
return ret;

@@ -42,7 +49,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
if (ret)
return ret;

-   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+   return lock_owner == proc_id;
 }

 static void qcom_hwspinlock_unlock(struct hwspinlock *lock)


The unlock path checks proc_id so we need to update the path there too.


Good point. I missed it.


--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] Lock 7 is cpuidle specific, use non-generic value for locking

2015-03-12 Thread Lina Iyer

On Thu, Mar 12 2015 at 14:49 -0600, Andy Gross wrote:

On Thu, Mar 12, 2015 at 01:38:28PM -0600, Lina Iyer wrote:

snip


 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
struct regmap_field *field = lock-priv;
u32 lock_owner;
int ret;
+   u32 proc_id;

-   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   proc_id = hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+   QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id():
+   QCOM_MUTEX_APPS_PROC_ID;
+
+   ret = regmap_field_write(field, proc_id);


I think I'd rather have a qcom specific function and EXPORT_SYMBOL that to deal
with this special case.


I was going back and forth between a function and inlining this here.
But Stephen just made a good point that this is needed for unlock as
well. A function would be good.



if (ret)
return ret;

@@ -42,7 +49,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
if (ret)
return ret;

-   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+   return lock_owner == proc_id;
 }

 static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
--
2.1.0



--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] Lock 7 is cpuidle specific, use non-generic value for locking

2015-03-12 Thread Lina Iyer
---
 drivers/hwspinlock/qcom_hwspinlock.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/hwspinlock/qcom_hwspinlock.c 
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..7642524 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,23 @@
 
 #include hwspinlock_internal.h
 
-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS   32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET  128
+#define QCOM_CPUIDLE_LOCK  7
+#define QCOM_MUTEX_NUM_LOCKS   32
 
 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
struct regmap_field *field = lock-priv;
u32 lock_owner;
int ret;
+   u32 proc_id;
 
-   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   proc_id = hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+   QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id():
+   QCOM_MUTEX_APPS_PROC_ID;
+
+   ret = regmap_field_write(field, proc_id);
if (ret)
return ret;
 
@@ -42,7 +49,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
if (ret)
return ret;
 
-   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+   return lock_owner == proc_id;
 }
 
 static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
-- 
2.1.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] hwspinlock: qcom: Add support for Qualcomm HW Mutex block

2015-03-12 Thread Lina Iyer

On Fri, Feb 27 2015 at 15:30 -0700, Bjorn Andersson wrote:

Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
SoCs.

Based on initial effort by Kumar Gala ga...@codeaurora.org

Signed-off-by: Bjorn Andersson bjorn.anders...@sonymobile.com
---



[...]


+#include hwspinlock_internal.h
+
+#define QCOM_MUTEX_APPS_PROC_ID1

Hi Bjorn,

Not all locks use 1 to indicate its locked. For example lock index 7 is
used by cpuidle driver between HLOS and SCM. It uses a write value of
(128 + smp_processor_id()) to lock.

A cpu acquires the remote spin lock, and calls into SCM to terminate the
power down sequence while passing the state of the L2. The lock help
guarantee the last core to hold the spinlock to have the most up to date
value for the L2 flush flag.


+#define QCOM_MUTEX_NUM_LOCKS   32


Also, talking to Jeff it seems like that out of the 32 locks defined
only 8 is accessible from Linux. So its unnecessary and probably
incorrect to assume that there are 32 locks available.

Thanks,
Lina


+{
+   struct regmap_field *field = lock-priv;
+   u32 lock_owner;
+   int ret;
+
+   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   if (ret)
+   return ret;
+
+   ret = regmap_field_read(field, lock_owner);
+   if (ret)
+   return ret;
+
+   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+}
+


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] hwspinlock: qcom: Add support for Qualcomm HW Mutex block

2015-03-12 Thread Lina Iyer

On Thu, Mar 12 2015 at 13:43 -0600, Andy Gross wrote:

On Thu, Mar 12, 2015 at 01:31:50PM -0600, Lina Iyer wrote:

On Fri, Feb 27 2015 at 15:30 -0700, Bjorn Andersson wrote:
Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
SoCs.

Based on initial effort by Kumar Gala ga...@codeaurora.org

Signed-off-by: Bjorn Andersson bjorn.anders...@sonymobile.com
---


[...]

+#include hwspinlock_internal.h
+
+#define QCOM_MUTEX_APPS_PROC_ID1
Hi Bjorn,

Not all locks use 1 to indicate its locked. For example lock index 7 is
used by cpuidle driver between HLOS and SCM. It uses a write value of
(128 + smp_processor_id()) to lock.


So this was the lock_rlock_id API?


Correct.


A cpu acquires the remote spin lock, and calls into SCM to terminate the
power down sequence while passing the state of the L2. The lock help
guarantee the last core to hold the spinlock to have the most up to date
value for the L2 flush flag.

+#define QCOM_MUTEX_NUM_LOCKS   32

Also, talking to Jeff it seems like that out of the 32 locks defined
only 8 is accessible from Linux. So its unnecessary and probably
incorrect to assume that there are 32 locks available.


Out of curiosity, this is a TZ thing?  If so, we'd expect issues if someone
decides to utilize resources that, while technically are present, are unusable
by that processor.  This is not that much different from someone misconfiguring
an EE on a DMA controller.


Per Jeff, the protection unit doesnt generally allow access to locks  8
and shouldnt be allowed and in some SoC's where they dont have the
protection, it might still be a bad idea. It would be safer to restrict to
8, than allow all 32 and hope somebody doesnt do the wrong thing.


+{
+   struct regmap_field *field = lock-priv;
+   u32 lock_owner;
+   int ret;
+
+   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   if (ret)
+   return ret;
+
+   ret = regmap_field_read(field, lock_owner);
+   if (ret)
+   return ret;
+
+   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+}
+



--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] Lock 7 is cpuidle specific, use non-generic value for locking

2015-03-12 Thread Lina Iyer

On Thu, Mar 12 2015 at 15:12 -0600, Stephen Boyd wrote:

On 03/12/15 13:48, Lina Iyer wrote:

On Thu, Mar 12 2015 at 14:35 -0600, Stephen Boyd wrote:

On 03/12/15 12:38, Lina Iyer wrote:

---


sign off?


:) I was just hacking it to make it easier to understand. Sure.


 drivers/hwspinlock/qcom_hwspinlock.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/hwspinlock/qcom_hwspinlock.c
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..7642524 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,23 @@

 #include hwspinlock_internal.h

-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET128
+#define QCOM_CPUIDLE_LOCK7
+#define QCOM_MUTEX_NUM_LOCKS32

 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
 struct regmap_field *field = lock-priv;
 u32 lock_owner;
 int ret;
+u32 proc_id;

-ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+proc_id = hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id():


So we assume that the caller will always be the CPU that is locking the
lock? Also, do we assume that the remote side knows our CPU scheme here?
smp_processor_id() returns the logical CPU and not the physical CPU
number so hopefully the remote side doesn't care about logical CPU
numbers being written to the lock value.


The remote side (SCM) doesnt care the value written. We use 128+cpu to
be unique in Linux(128 is to make sure it doesnt clash with predefined
values used across by other processors.




It looks like the remote side unlocks it too? It doesn't seem like this
will work with the framework very well. The framework has a kernel
spinlock attached to the hwspinlock so when we lock the hwspinlock we
also lock the kernel spinlock and we only release the kernel spinlock
when the kernel unlocks the hwspinlock. In this case it seems like
cpuidle wants to have it's own kernel spinlock and just use the trylock
loop part of __hwspin_lock_timeout() without taking any kernel side
locks. Plus it wants to write a specific value to the lock.


Right.
Just noticed that part of the hwspinlock. Yes SCM unlocks the
hwspinlock. So I cannot hold any lock in Linux. May need changes in the
hwspinlock framework. Seems like an additional flag in hwspinlock to not
lock any in the trylock path work work. Hmm




--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] hwspinlock: qcom: Add support for Qualcomm HW Mutex block

2015-03-12 Thread Lina Iyer

On Fri, Feb 27 2015 at 15:30 -0700, Bjorn Andersson wrote:

Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
SoCs.

Based on initial effort by Kumar Gala ga...@codeaurora.org

Signed-off-by: Bjorn Andersson bjorn.anders...@sonymobile.com
+config HWSPINLOCK_QCOM
+   tristate Qualcomm Hardware Spinlock device
+   depends on ARCH_QCOM
+   select HWSPINLOCK


select MFD_SYSCON as well, perhaps?
We seem to be dependent on it.


+   help
+ Say y here to support the Qualcomm Hardware Mutex functionality, which
+ provides a synchronisation mechanism for the various processors on
+ the SoC.
+
+ If unsure, say N.
+


Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH V2 7/8] ARM: cpuidle: Register per cpuidle device

2015-03-19 Thread Lina Iyer

On Wed, Mar 18 2015 at 12:46 -0600, Daniel Lezcano wrote:

Some architectures have some cpus which does not support idle states.

Let the underlying low level code to return -ENOSYS when it is not
possible to set an idle state.

Signed-off-by: Daniel Lezcano daniel.lezc...@linaro.org
---
drivers/cpuidle/cpuidle-arm.c | 45 +--
1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 1c94b88..0682ed0 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -17,11 +17,14 @@
#include linux/kernel.h
#include linux/module.h
#include linux/of.h
+#include linux/slab.h

#include asm/cpuidle.h

#include dt_idle_states.h

+static DEFINE_PER_CPU(struct cpuidle_device, *cpuidle_arm_dev);


Is a per-cpu variable needed? There seems to be no per-cpu access, other
than at init.


+
/*
 * arm_enter_idle_state - Programs CPU to enter the specified state
 *
@@ -94,6 +97,7 @@ static int __init arm_idle_init(void)
{
int cpu, ret;
struct cpuidle_driver *drv = arm_idle_driver;
+   struct cpuidle_device *dev;

/*
 * Initialize idle states data, starting at index 1.
@@ -105,18 +109,55 @@ static int __init arm_idle_init(void)
if (ret = 0)
return ret ? : -ENODEV;

+   ret = cpuidle_register_driver(drv);
+   if (ret) {
+   pr_err(Failed to register cpuidle driver\n);
+   return ret;
+   }
+
/*
 * Call arch CPU operations in order to initialize
 * idle states suspend back-end specific data
 */
for_each_possible_cpu(cpu) {
ret = arm_cpuidle_init(cpu);
+
+   /* This cpu does not support any idle states */
+   if (ret == -ENOSYS)
+   continue;
+
if (ret) {
pr_err(CPU %d failed to init idle CPU ops\n, cpu);
-   return ret;
+   goto out_fail;
+   }
+
+   dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+   if (!dev) {
+   pr_err(Failed to allocate cpuidle device\n);
+   goto out_fail;
+   }
+
+   dev-cpu = cpu;
+   per_cpu(cpuidle_arm_dev, cpu) = dev;
+
+   ret = cpuidle_register_device(dev);
+   if (ret) {
+   pr_err(Failed to register cpuidle device for CPU %d\n,
+  cpu);
+   kfree(dev);
+   goto out_fail;
}
}
+out:
+   return ret;

-   return cpuidle_register(drv, NULL);
+out_fail:
+   for (cpu--; cpu = 0; cpu--) {
+   dev = per_cpu(cpuidle_arm_dev, cpu);
+   cpuidle_unregister_device(dev);
+   kfree(dev);
+   }
+   cpuidle_unregister_driver(drv);
+   goto out;
}
device_initcall(arm_idle_init);
--
1.9.1


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH V2 7/8] ARM: cpuidle: Register per cpuidle device

2015-03-19 Thread Lina Iyer

On Thu, Mar 19 2015 at 09:33 -0600, Daniel Lezcano wrote:

On 03/19/2015 04:31 PM, Lina Iyer wrote:

On Wed, Mar 18 2015 at 12:46 -0600, Daniel Lezcano wrote:

Some architectures have some cpus which does not support idle states.

Let the underlying low level code to return -ENOSYS when it is not
possible to set an idle state.

Signed-off-by: Daniel Lezcano daniel.lezc...@linaro.org
---
drivers/cpuidle/cpuidle-arm.c | 45
+--
1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-arm.c
b/drivers/cpuidle/cpuidle-arm.c
index 1c94b88..0682ed0 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -17,11 +17,14 @@
#include linux/kernel.h
#include linux/module.h
#include linux/of.h
+#include linux/slab.h

#include asm/cpuidle.h

#include dt_idle_states.h

+static DEFINE_PER_CPU(struct cpuidle_device, *cpuidle_arm_dev);


Is a per-cpu variable needed? There seems to be no per-cpu access, other
than at init.


:)

Actually it is the cpuidle framework which is using the per cpu variable.



But this is static pointer, I can see that struct cpuidle_device * being
used by cpuidle framework.

It gets stored here?

DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);

But we dont need to save it here, for in this file, there is no per-cpu
access, other than when the registration fails.



+
/*
* arm_enter_idle_state - Programs CPU to enter the specified state
*
@@ -94,6 +97,7 @@ static int __init arm_idle_init(void)
{
   int cpu, ret;
   struct cpuidle_driver *drv = arm_idle_driver;
+struct cpuidle_device *dev;

   /*
* Initialize idle states data, starting at index 1.
@@ -105,18 +109,55 @@ static int __init arm_idle_init(void)
   if (ret = 0)
   return ret ? : -ENODEV;

+ret = cpuidle_register_driver(drv);
+if (ret) {
+pr_err(Failed to register cpuidle driver\n);
+return ret;
+}
+
   /*
* Call arch CPU operations in order to initialize
* idle states suspend back-end specific data
*/
   for_each_possible_cpu(cpu) {
   ret = arm_cpuidle_init(cpu);
+
+/* This cpu does not support any idle states */
+if (ret == -ENOSYS)
+continue;
+
   if (ret) {
   pr_err(CPU %d failed to init idle CPU ops\n, cpu);
-return ret;
+goto out_fail;
+}
+
+dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+if (!dev) {
+pr_err(Failed to allocate cpuidle device\n);
+goto out_fail;
+}
+
+dev-cpu = cpu;
+per_cpu(cpuidle_arm_dev, cpu) = dev;
+
+ret = cpuidle_register_device(dev);
+if (ret) {
+pr_err(Failed to register cpuidle device for CPU %d\n,
+   cpu);
+kfree(dev);
+goto out_fail;
   }
   }
+out:
+return ret;

-return cpuidle_register(drv, NULL);
+out_fail:
+for (cpu--; cpu = 0; cpu--) {
+dev = per_cpu(cpuidle_arm_dev, cpu);
+cpuidle_unregister_device(dev);
+kfree(dev);
+}
+cpuidle_unregister_driver(drv);
+goto out;
}
device_initcall(arm_idle_init);
--
1.9.1




--
http://www.linaro.org/ Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  http://www.facebook.com/pages/Linaro Facebook |
http://twitter.com/#!/linaroorg Twitter |
http://www.linaro.org/linaro-blog/ Blog


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] mm/migrate: Mark unmap_and_move() noinline to avoid ICE in gcc 4.7.3

2015-04-02 Thread Lina Iyer

On Thu, Apr 02 2015 at 15:12 -0600, Kevin Hilman wrote:

On Thu, Apr 2, 2015 at 12:12 PM, Lina Iyer lina.i...@linaro.org wrote:

On Wed, Apr 01 2015 at 15:57 -0600, Kevin Hilman wrote:


Andrew Morton a...@linux-foundation.org writes:


On Wed, 01 Apr 2015 10:47:49 +0100 Marc Zyngier marc.zyng...@arm.com
wrote:


 -static int unmap_and_move(new_page_t get_new_page, free_page_t
 put_new_page,
 - unsigned long private, struct page *page, int
 force,
 - enum migrate_mode mode)
 +static noinline int unmap_and_move(new_page_t get_new_page,
 +free_page_t put_new_page,
 +unsigned long private, struct page
 *page,
 +int force, enum migrate_mode mode)
  {
   int rc = 0;
   int *result = NULL;


Ouch. That's really ugly. And on 32bit ARM, we end-up spilling half of
the parameters on the stack, which is not going to help performance
either (not that this would be useful on 32bit ARM anyway...).

Any chance you could make this dependent on some compiler detection
mechanism?



With my arm compiler (gcc-4.4.4) the patch makes no difference -
unmap_and_move() isn't being inlined anyway.

How does this look?

Kevin, could you please retest?  I might have fat-fingered something...



Your patch on top of Geert's still compiles fine for me with gcc-4.7.3.
However, I'm not sure how specific we can be on the versions.

/me goes to test a few more compilers...   OK...

ICE: 4.7.1, 4.7.3, 4.8.3
OK: 4.6.3, 4.9.2, 4.9.3

The diff below[2] on top of yours compiles fine here and at least covers
the compilers I *know* to trigger the ICE.



I see ICE on arm-linux-gnueabi-gcc (Ubuntu/Linaro 4.7.4-2ubuntu1) 4.7.4



Thanks for checking.  I'm assuming my patch fixes it for your since
that should catch any 4.7.x compiler.


Yes, thank you. This fixes it on 4.7.4


Kevin

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] mm/migrate: Mark unmap_and_move() noinline to avoid ICE in gcc 4.7.3

2015-04-02 Thread Lina Iyer

On Wed, Apr 01 2015 at 15:57 -0600, Kevin Hilman wrote:

Andrew Morton a...@linux-foundation.org writes:


On Wed, 01 Apr 2015 10:47:49 +0100 Marc Zyngier marc.zyng...@arm.com wrote:


 -static int unmap_and_move(new_page_t get_new_page, free_page_t put_new_page,
 -  unsigned long private, struct page *page, int force,
 -  enum migrate_mode mode)
 +static noinline int unmap_and_move(new_page_t get_new_page,
 + free_page_t put_new_page,
 + unsigned long private, struct page *page,
 + int force, enum migrate_mode mode)
  {
int rc = 0;
int *result = NULL;


Ouch. That's really ugly. And on 32bit ARM, we end-up spilling half of
the parameters on the stack, which is not going to help performance
either (not that this would be useful on 32bit ARM anyway...).

Any chance you could make this dependent on some compiler detection
mechanism?


With my arm compiler (gcc-4.4.4) the patch makes no difference -
unmap_and_move() isn't being inlined anyway.

How does this look?

Kevin, could you please retest?  I might have fat-fingered something...


Your patch on top of Geert's still compiles fine for me with gcc-4.7.3.
However, I'm not sure how specific we can be on the versions.

/me goes to test a few more compilers...   OK...

ICE: 4.7.1, 4.7.3, 4.8.3
OK: 4.6.3, 4.9.2, 4.9.3

The diff below[2] on top of yours compiles fine here and at least covers
the compilers I *know* to trigger the ICE.


I see ICE on 
arm-linux-gnueabi-gcc (Ubuntu/Linaro 4.7.4-2ubuntu1) 4.7.4




Kevin


[1]
diff --git a/mm/migrate.c b/mm/migrate.c
index 25fd7f6291de..6e15ae3248e0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -901,10 +901,10 @@ out:
}

/*
- * gcc-4.7.3 on arm gets an ICE when inlining unmap_and_move().  Work around
+ * gcc 4.7 and 4.8 on arm gets an ICE when inlining unmap_and_move().  Work 
around
 * it.
 */
-#if GCC_VERSION == 40703  defined(CONFIG_ARM)
+#if (GCC_VERSION = 40700  GCC_VERSION  40900)  defined(CONFIG_ARM)
#define ICE_noinline noinline
#else
#define ICE_noinline

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH RFC] hwspinlock: Don't take software spinlock before hwspinlock

2015-05-01 Thread Lina Iyer
Some uses of the hwspinlock could be that one entity acquires the lock
and the other entity releases the lock. This allows for a serialized
traversal path from the locking entity to the other.

For example, the cpuidle entry from Linux to the firmware to power down
the core, can be serialized across the context switch by locking the
hwspinlock in Linux and releasing it in the firmware.

Do not force the caller of __hwspin_trylock() to acquire a kernel
spinlock before acquiring the hwspinlock.

Cc: Jeffrey Hugo jh...@codeaurora.org
Cc: Ohad Ben-Cohen o...@wizery.com
Cc: Suman Anna s-a...@ti.com
Cc: Andy Gross agr...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 drivers/hwspinlock/hwspinlock_core.c | 56 
 include/linux/hwspinlock.h   |  1 +
 2 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/drivers/hwspinlock/hwspinlock_core.c 
b/drivers/hwspinlock/hwspinlock_core.c
index 461a0d7..bdc59f2 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -105,30 +105,34 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, 
unsigned long *flags)
 *problems with hwspinlock usage (e.g. scheduler checks like
 *'scheduling while atomic' etc.)
 */
-   if (mode == HWLOCK_IRQSTATE)
-   ret = spin_trylock_irqsave(hwlock-lock, *flags);
-   else if (mode == HWLOCK_IRQ)
-   ret = spin_trylock_irq(hwlock-lock);
-   else
-   ret = spin_trylock(hwlock-lock);
+   if (mode != HWLOCK_NOLOCK) {
+   if (mode == HWLOCK_IRQSTATE)
+   ret = spin_trylock_irqsave(hwlock-lock, *flags);
+   else if (mode == HWLOCK_IRQ)
+   ret = spin_trylock_irq(hwlock-lock);
+   else
+   ret = spin_trylock(hwlock-lock);
 
-   /* is lock already taken by another context on the local cpu ? */
-   if (!ret)
-   return -EBUSY;
+   /* is lock already taken by another context on the local cpu? */
+   if (!ret)
+   return -EBUSY;
+   }
 
/* try to take the hwspinlock device */
ret = hwlock-bank-ops-trylock(hwlock);
 
-   /* if hwlock is already taken, undo spin_trylock_* and exit */
-   if (!ret) {
-   if (mode == HWLOCK_IRQSTATE)
-   spin_unlock_irqrestore(hwlock-lock, *flags);
-   else if (mode == HWLOCK_IRQ)
-   spin_unlock_irq(hwlock-lock);
-   else
-   spin_unlock(hwlock-lock);
+   if (mode != HWLOCK_NOLOCK) {
+   /* if hwlock is already taken, undo spin_trylock_* and exit */
+   if (!ret) {
+   if (mode == HWLOCK_IRQSTATE)
+   spin_unlock_irqrestore(hwlock-lock, *flags);
+   else if (mode == HWLOCK_IRQ)
+   spin_unlock_irq(hwlock-lock);
+   else
+   spin_unlock(hwlock-lock);
 
-   return -EBUSY;
+   return -EBUSY;
+   }
}
 
/*
@@ -247,13 +251,15 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, 
unsigned long *flags)
 
hwlock-bank-ops-unlock(hwlock);
 
-   /* Undo the spin_trylock{_irq, _irqsave} called while locking */
-   if (mode == HWLOCK_IRQSTATE)
-   spin_unlock_irqrestore(hwlock-lock, *flags);
-   else if (mode == HWLOCK_IRQ)
-   spin_unlock_irq(hwlock-lock);
-   else
-   spin_unlock(hwlock-lock);
+   if (mode != HWLOCK_NOLOCK) {
+   /* Undo the spin_trylock{_irq, _irqsave} called while locking */
+   if (mode == HWLOCK_IRQSTATE)
+   spin_unlock_irqrestore(hwlock-lock, *flags);
+   else if (mode == HWLOCK_IRQ)
+   spin_unlock_irq(hwlock-lock);
+   else
+   spin_unlock(hwlock-lock);
+   }
 }
 EXPORT_SYMBOL_GPL(__hwspin_unlock);
 
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index 3343298..219b333 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -24,6 +24,7 @@
 /* hwspinlock mode argument */
 #define HWLOCK_IRQSTATE0x01/* Disable interrupts, save state */
 #define HWLOCK_IRQ 0x02/* Disable interrupts, don't save state */
+#define HWLOCK_NOLOCK  0xFF/* Dont take any lock */
 
 struct device;
 struct hwspinlock;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

2015-05-01 Thread Lina Iyer

On Fri, May 01 2015 at 11:27 -0600, Jeffrey Hugo wrote:

On 5/1/2015 11:06 AM, Lina Iyer wrote:


diff --git a/drivers/hwspinlock/qcom_hwspinlock.c 
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..043c62c 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,26 @@

 #include hwspinlock_internal.h

-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS   32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET  128
+#define QCOM_CPUIDLE_LOCK  7
+#define QCOM_MUTEX_NUM_LOCKS   32
+


This part of the diff doesn't look right.  Why is it showing that 
QCOM_MUTEX_APPS_PROC_ID and QCOM_MUTEX_NUM_LOCKS are deleted and added 
lines?  Shouldn't they be unchanged by this patch?



Sigh. I must have updated the tabs to play nice. Will fix in the next
spin.

Thanks for the review.

--Lina


--
Jeffrey Hugo
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

2015-05-01 Thread Lina Iyer
Hwspinlocks are widely used between processors in an SoC, and also
between elevation levels within in the same processor.  QCOM SoC's use
hwspinlock to serialize entry into a low power mode when the context
switches from Linux to secure monitor.

Lock #7 has been assigned for this purpose. In order to differentiate
between one cpu core holding a lock while another cpu is contending for
the same lock, the proc id written into the lock is (128 + cpu id). This
makes it unique value among the cpu cores and therefore when a core
locks the hwspinlock, other cores would wait for the lock to be released
since they would have a different proc id.  This value is specific for
the lock #7 only.

Cc: Jeffrey Hugo jh...@codeaurora.org
Cc: Bjorn Andersson bjorn.anders...@sonymobile.com
Cc: Andy Gross agr...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 drivers/hwspinlock/qcom_hwspinlock.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/hwspinlock/qcom_hwspinlock.c 
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..043c62c 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,26 @@
 
 #include hwspinlock_internal.h
 
-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS   32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET  128
+#define QCOM_CPUIDLE_LOCK  7
+#define QCOM_MUTEX_NUM_LOCKS   32
+
+static inline u32 __qcom_get_proc_id(struct hwspinlock *lock)
+{
+   return hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+   (QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id()) :
+   QCOM_MUTEX_APPS_PROC_ID;
+}
 
 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
struct regmap_field *field = lock-priv;
u32 lock_owner;
int ret;
+   u32 proc_id = __qcom_get_proc_id(lock);
 
-   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   ret = regmap_field_write(field, proc_id);
if (ret)
return ret;
 
@@ -42,7 +52,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
if (ret)
return ret;
 
-   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+   return lock_owner == proc_id;
 }
 
 static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
@@ -57,7 +67,7 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
return;
}
 
-   if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) {
+   if (lock_owner != __qcom_get_proc_id(lock)) {
pr_err(%s: spinlock not owned by us (actual owner is %d)\n,
__func__, lock_owner);
}
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC] hwspinlock: Don't take software spinlock before hwspinlock

2015-05-11 Thread Lina Iyer

On Sat, May 09 2015 at 03:25 -0600, Ohad Ben-Cohen wrote:

Hi Lina,

On Fri, May 1, 2015 at 8:07 PM, Lina Iyer lina.i...@linaro.org wrote:

Some uses of the hwspinlock could be that one entity acquires the lock
and the other entity releases the lock. This allows for a serialized
traversal path from the locking entity to the other.

For example, the cpuidle entry from Linux to the firmware to power down
the core, can be serialized across the context switch by locking the
hwspinlock in Linux and releasing it in the firmware.

Do not force the caller of __hwspin_trylock() to acquire a kernel
spinlock before acquiring the hwspinlock.


Let's discuss whether we really want to expose this functionality
under the same hwspinlock API or not.

In this new mode, unlike previously, users will now be able to sleep
after taking the lock, and others trying to take the lock might poll
the hardware for a long period of time without the ability to sleep
while waiting for the lock. It almost sounds like you were looking for
some hwmutex functionality.

What do you think about this?


I agree, that it opens up a possiblity that user may sleep after holding
a hw spinlock.  But really, why should it prevents us from using it as a
hw mutex, if the need is legitimate?

We could make a check that the caller with NO_LOCK option calls only
with irq disabled, if thats required.

Thanks for the review.

-- Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC] hwspinlock: Don't take software spinlock before hwspinlock

2015-05-18 Thread Lina Iyer

On Sat, May 16 2015 at 03:03 -0600, Ohad Ben-Cohen wrote:

On Mon, May 11, 2015 at 5:46 PM, Lina Iyer lina.i...@linaro.org wrote:

On Sat, May 09 2015 at 03:25 -0600, Ohad Ben-Cohen wrote:

On Fri, May 1, 2015 at 8:07 PM, Lina Iyer lina.i...@linaro.org wrote:
Let's discuss whether we really want to expose this functionality
under the same hwspinlock API or not.

In this new mode, unlike previously, users will now be able to sleep
after taking the lock, and others trying to take the lock might poll
the hardware for a long period of time without the ability to sleep
while waiting for the lock. It almost sounds like you were looking for
some hwmutex functionality.


I agree, that it opens up a possiblity that user may sleep after holding
a hw spinlock.  But really, why should it prevents us from using it as a
hw mutex, if the need is legitimate?


If we want hw mutex functionality, let's discuss how to expose it.
Exposing it using the existing hw spinlock API might not be ideal, as
users might get confused.

Additionally, there are hardware IP locking blocks out there which
encourage users to sleep while waiting for a lock, by providing
interrupt functionality to wake them up when the lock is freed. So if
we choose to add a hw mutex API it might be used by others in the
future too (though this reason alone is not why we would choose to add
it now of course).


Okay, the API seems to want to dictate what kind of flags be specified
for __try_lock(), FLAG_NONE, in my mind, seems to fall into the same
classification. But sure, we can discuss a different form of achieving
the same thing.

Do you have any ideas?


API discussions aside, what do you want to happen in your scenario
while the lock is taken? are you OK with other users spinning on the
lock waiting for it to be released? IIUC that might mean processors
spinning for a non-negligible period of time?


The lock in question is used differently than traditional locks across
processors. This lock helps synchronizes context transition from
non-secure to secure on the same processor.

The usecase, goes like this. In cpuidle, any core can be the last core
to power down. The last man also holds the responsibility of shutting
down shared resources like caches etc. The way the power down of a core
works is, there are some high level decisions made in Linux and these
decisions (like to flush and invalidate caches) etc gets transferred
over to the the secure layer. The secure layer executes the ARM WFI that
powers down the cpu, but uses these decisions passed into to determine
if the cache needs to be invalidated upon wakeup etc.

There is a possible race condition between what Linux thinks is the last
core, vs what secure layer thinks is the last core. Lets say, two cores
c0, c1 are going down. c1 is the second last core to go down from Linux
as such, will not carry information about shared resources when making
the SCM call. c1  made the SCM call, but is stuck handling some FIQs. In
the meanwhile c0, goes idle and since its the last core in Linux,
figures out the state of the shared resources. c0 calls into SCM, and
ends up powering down earlier than c1. Per secure layer, the last core
to go down is c1 and the votes of the shared resources are considered
from that core. Things like cache invalidation without flush may happen
as a result of this inconsistency of last man view point.

The way we have solved it, Linux acquires a hw spinlock for each core,
when calling into SCM and the secure monitor releases the spinlock. At
any given time, only one core can switch the context from Linux to
secure for power down operations. This guarantees the last man is
synchronized between both Linux and secure. Another core may be spinning
waiting for hw mutex, but they all happen serialized. This mutex is held
in an irq disable context in cpuidle.

There may be another processor spining to wait on hw mutex, but there
isnt much to do otherwise, because the only operation at this time while
holding the lock is to call into SCM and that would unlock the mutex.

Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC PATCH 0/5] Add smp booting support for Qualcomm ARMv8 SoCs

2015-04-15 Thread Lina Iyer

On Tue, Apr 14 2015 at 16:32 -0600, Lorenzo Pieralisi wrote:

On Tue, Apr 14, 2015 at 03:21:17PM +0100, Kumar Gala wrote:

[...]


 Looking beyond this set of patches, I can foresee that you won't care
 about the generic arm64 cpuidle driver either, or more precisely the
 separation between cpuidle subsystem+driver and the SoC-specific
 back-end (cpu_operations).

That's probably true for what I guess are a number of reasons.  I'm guessing 
the arm64 cpuidle driver expects PSCI.


Wrap lines sensibly please.

The arm64 cpuidle driver, that is now arm generic cpuidle driver does
not expect anything apart from an enable-method (and you pulled
part of its back-end implementation for arm32 Qualcomm platforms, FYI).


The backend for this SoC would leverage the same platform code as ARM32.
The cpu_operations callbacks for init and suspend will call into the the
same platform functions used by arm32 QCOM SoCs.

Thanks,
Lina


It took years to consolidate it and the main reason was the lack of
standard interfaces for power down/up sequences that this patchset of
yours wants to promote in arm64 world.

The lack of standard power interfaces may not have been an issue for you,
who cares about Qualcomm code, it has been a sore issue for people
trying to generalize things across ARM platforms in the kernel, which is
the only sensible way forward.

PSCI is a standard interface (and Qualcomm are already contributing to
it, for the records) that can certainly be extended, and you are welcome
to contribute to it, but certainly not ignored.

Thanks,
Lorenzo
--
To unsubscribe from this list: send the line unsubscribe linux-arm-msm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC] hwspinlock: Don't take software spinlock before hwspinlock

2015-05-20 Thread Lina Iyer

On Tue, May 19 2015 at 14:13 -0600, Andy Gross wrote:

On Mon, May 18, 2015 at 09:03:02AM -0600, Lina Iyer wrote:

On Sat, May 16 2015 at 03:03 -0600, Ohad Ben-Cohen wrote:
On Mon, May 11, 2015 at 5:46 PM, Lina Iyer lina.i...@linaro.org wrote:
On Sat, May 09 2015 at 03:25 -0600, Ohad Ben-Cohen wrote:
On Fri, May 1, 2015 at 8:07 PM, Lina Iyer lina.i...@linaro.org wrote:
Let's discuss whether we really want to expose this functionality
under the same hwspinlock API or not.

In this new mode, unlike previously, users will now be able to sleep
after taking the lock, and others trying to take the lock might poll
the hardware for a long period of time without the ability to sleep
while waiting for the lock. It almost sounds like you were looking for
some hwmutex functionality.

I agree, that it opens up a possiblity that user may sleep after holding
a hw spinlock.  But really, why should it prevents us from using it as a
hw mutex, if the need is legitimate?

If we want hw mutex functionality, let's discuss how to expose it.
Exposing it using the existing hw spinlock API might not be ideal, as
users might get confused.

Additionally, there are hardware IP locking blocks out there which
encourage users to sleep while waiting for a lock, by providing
interrupt functionality to wake them up when the lock is freed. So if
we choose to add a hw mutex API it might be used by others in the
future too (though this reason alone is not why we would choose to add
it now of course).

Okay, the API seems to want to dictate what kind of flags be specified
for __try_lock(), FLAG_NONE, in my mind, seems to fall into the same
classification. But sure, we can discuss a different form of achieving
the same thing.

Do you have any ideas?


So let's say we had this hwmutex API.  Are you advocating that we separate out
the hardware spinlock into hwmutex and then make calls to acquire/release the
hwmutex in the hwspinlock?  And then we'd use the hwmutex acquire/release when
we don't want the wrapped sw spinlock.

Seems like a lot of trouble when all we want is a behavior change on the use of
the sw spinlock.


I see the effort needed for that.
I am not advocating any thing else other than a flag to solve the
problem. I was hoping if this wasnt acceptable, somebody else has a
better idea.



API discussions aside, what do you want to happen in your scenario
while the lock is taken? are you OK with other users spinning on the
lock waiting for it to be released? IIUC that might mean processors
spinning for a non-negligible period of time?

The lock in question is used differently than traditional locks across
processors. This lock helps synchronizes context transition from
non-secure to secure on the same processor.

The usecase, goes like this. In cpuidle, any core can be the last core
to power down. The last man also holds the responsibility of shutting
down shared resources like caches etc. The way the power down of a core
works is, there are some high level decisions made in Linux and these
decisions (like to flush and invalidate caches) etc gets transferred
over to the the secure layer. The secure layer executes the ARM WFI that
powers down the cpu, but uses these decisions passed into to determine
if the cache needs to be invalidated upon wakeup etc.

There is a possible race condition between what Linux thinks is the last
core, vs what secure layer thinks is the last core. Lets say, two cores
c0, c1 are going down. c1 is the second last core to go down from Linux
as such, will not carry information about shared resources when making
the SCM call. c1  made the SCM call, but is stuck handling some FIQs. In
the meanwhile c0, goes idle and since its the last core in Linux,
figures out the state of the shared resources. c0 calls into SCM, and
ends up powering down earlier than c1. Per secure layer, the last core
to go down is c1 and the votes of the shared resources are considered
from that core. Things like cache invalidation without flush may happen
as a result of this inconsistency of last man view point.

The way we have solved it, Linux acquires a hw spinlock for each core,
when calling into SCM and the secure monitor releases the spinlock. At
any given time, only one core can switch the context from Linux to
secure for power down operations. This guarantees the last man is
synchronized between both Linux and secure. Another core may be spinning
waiting for hw mutex, but they all happen serialized. This mutex is held
in an irq disable context in cpuidle.

There may be another processor spining to wait on hw mutex, but there
isnt much to do otherwise, because the only operation at this time while
holding the lock is to call into SCM and that would unlock the mutex.


In this use case you have an asymmetric use of the APIs. lock but no unlock.
And this breaks the sw spinlock usage.


Thats correct. Linux locks, firmware unlocks. While this is not the ideal
locking scenario, this is the only way to ensure that there are no races

[PATCH RFC v2 1/2] hwspinlock: Introduce raw capability for hwspinlocks

2015-06-09 Thread Lina Iyer
The hwspinlock framework, uses a s/w spin lock around the hw spinlock to
ensure that only process acquires the lock at any time. This is the most
general use case. A special case is where a hwspinlock may be acquired
in Linux and a remote entity may release the lock. In such a case, the
s/w spinlock may never be unlocked as Linux would never call
hwspin_unlock on the hwlock.

This special case is needed for serializing the processor across context
switches from Linux to firmware. Multiple cores may enter cpu idle and
would switch context to firmware to power off. A cpu holding the
hwspinlock would cause other cpus to wait to acquire the lock, until the
lock is released by the firmware. The last core to power down per Linux
has the correct state of the shared resources and should be the one
considered by the firmware. However, a cpu may be stuck handling FIQs
and therefore the last man view of Linux and the firmware may differ. A
hwspinlock avoids this problem by serializing the entry from Linux to
firmware.

Introduce hwcaps member for hwspinlock_device. The hwcaps represents the
hw capability of each hwlock. The platform driver is responsible for
specifying this capability for each lock in the bank. A lock that has
HWL_CAP_ALLOW_RAW set, would indicate to the framework, the capability
for ensure locking correctness in the platform. Since no sw spinlock
guards the hwspinlock, it is the responsibility of the platform driver
to ensure that an unique value is written to the hwspinlock to ensure
locking correctness.

Drivers may use hwspin_trylock_raw() and hwspin_unlock_raw() api to lock
and unlock a hwlock with raw capability.

Cc: Jeffrey Hugo jh...@codeaurora.org
Cc: Ohad Ben-Cohen o...@wizery.com
Cc: Andy Gross agr...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 Documentation/hwspinlock.txt | 16 +++
 drivers/hwspinlock/hwspinlock_core.c | 75 +++-
 drivers/hwspinlock/hwspinlock_internal.h |  6 +++
 include/linux/hwspinlock.h   | 41 +
 4 files changed, 108 insertions(+), 30 deletions(-)

diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
index 62f7d4e..ca6de6c 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -122,6 +122,15 @@ independent, drivers.
  notably -EBUSY if the hwspinlock was already taken).
  The function will never sleep.
 
+  int hwspin_trylock_raw(struct hwspinlock *hwlock);
+   - attempt to lock a previously-assigned hwspinlock, but immediately fail if
+ it is already taken. The lock must have been declared by the platform
+ drv code with raw capability support.
+ Returns 0 on success and an appropriate error code otherwise (most
+ notably -EBUSY if the hwspinlock was already taken).
+ This function does not use a sw spinlock around the hwlock. The
+ responsiblity of the lock is guaranteed by the platform code.
+
   void hwspin_unlock(struct hwspinlock *hwlock);
- unlock a previously-locked hwspinlock. Always succeed, and can be called
  from any context (the function never sleeps). Note: code should _never_
@@ -144,6 +153,13 @@ independent, drivers.
  and the state of the local interrupts is restored to the state saved at
  the given flags. This function will never sleep.
 
+  void hwspin_unlock_raw(struct hwspinlock *hwlock);
+   - unlock a previously-locked hwspinlock. Always succeed, and can be called
+ from any context (the function never sleeps). Note: code should _never_
+ unlock an hwspinlock which is already unlocked (there is no protection
+ against this). The platform driver must support raw capability for this
+ hwlock.
+
   int hwspin_lock_get_id(struct hwspinlock *hwlock);
- retrieve id number of a given hwspinlock. This is needed when an
  hwspinlock is dynamically assigned: before it can be used to achieve
diff --git a/drivers/hwspinlock/hwspinlock_core.c 
b/drivers/hwspinlock/hwspinlock_core.c
index 461a0d7..18ed7cc 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -79,7 +79,10 @@ static DEFINE_MUTEX(hwspinlock_tree_lock);
  * whether he wants their previous state to be saved. It is up to the user
  * to choose the appropriate @mode of operation, exactly the same way users
  * should decide between spin_trylock, spin_trylock_irq and
- * spin_trylock_irqsave.
+ * spin_trylock_irqsave and even no spinlock, if the hwspinlock is always
+ * acquired in an interrupt disabled context. The platform driver that
+ * registers such a lock, would explicity specify the capability for the
+ * lock with the HWL_CAP_ALLOW_RAW capability flag.
  *
  * Returns 0 if we successfully locked the hwspinlock or -EBUSY if
  * the hwspinlock was already taken.
@@ -91,6 +94,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, 
unsigned long *flags)
 
BUG_ON(!hwlock);
BUG_ON(!flags  mode == HWLOCK_IRQSTATE

[PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-06-09 Thread Lina Iyer
This patch follows the discussion based on the first RFC series posted on the
mailing list [1]. The discussion resulted in a couple of directives for
hwspinlocks that do not want the framework imposing a s/w spinlock around the
hwspinlock.

i. The default should only be a s/w spinlock around the hwspinlock to ensure
correctness of locking.

ii. Existing users may not use raw capability, unless the platform registers
support for it.

iii. Platform driver for hwspinlock should dictate which locks can be operated
in raw mode.

iv. Platform driver and the hw holds the responsibility to ensure the
correctness of acquiring the hwspinlock.

This patchset implements these directives.

Changes since RFC v1:
- Introduce 'raw' capability for hwspinlocks.
- Platform code now has to explicitly specify the raw capability of a lock.
- Check to ensure that only those locks explicitly marked as raw capable can be
  locked/unlocked through the _raw api 
- QCOM patch for making lock #7 raw capable added.
- Add documentation

Thanks,
Lina

[1]. https://patches.linaro.org/47895/

Lina Iyer (2):
  hwspinlock: Introduce raw capability for hwspinlocks
  hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

 Documentation/hwspinlock.txt | 16 +++
 drivers/hwspinlock/hwspinlock_core.c | 75 +++-
 drivers/hwspinlock/hwspinlock_internal.h |  6 +++
 drivers/hwspinlock/qcom_hwspinlock.c | 22 +++---
 include/linux/hwspinlock.h   | 41 +
 5 files changed, 125 insertions(+), 35 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH RFC v2 2/2] hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

2015-06-09 Thread Lina Iyer
Hwspinlocks are widely used between processors in an SoC, and also
between elevation levels within in the same processor.  QCOM SoC's use
hwspinlock to serialize entry into a low power mode when the context
switches from Linux to secure monitor.

Lock #7 has been assigned for this purpose. In order to differentiate
between one cpu core holding a lock while another cpu is contending for
the same lock, the proc id written into the lock is (128 + cpu id). This
makes it unique value among the cpu cores and therefore when a core
locks the hwspinlock, other cores would wait for the lock to be released
since they would have a different proc id.  This value is specific for
the lock #7 only.

Declare lock #7 as raw capable, so the hwspinlock framework would not
enfore acquiring a s/w spinlock before acquiring the hwspinlock.

Cc: Jeffrey Hugo jh...@codeaurora.org
Cc: Bjorn Andersson bjorn.anders...@sonymobile.com
Cc: Andy Gross agr...@codeaurora.org
Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 drivers/hwspinlock/qcom_hwspinlock.c | 22 +-
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/hwspinlock/qcom_hwspinlock.c 
b/drivers/hwspinlock/qcom_hwspinlock.c
index 93b62e0..59278b0 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -25,16 +25,26 @@
 
 #include hwspinlock_internal.h
 
-#define QCOM_MUTEX_APPS_PROC_ID1
-#define QCOM_MUTEX_NUM_LOCKS   32
+#define QCOM_MUTEX_APPS_PROC_ID1
+#define QCOM_MUTEX_CPUIDLE_OFFSET  128
+#define QCOM_CPUIDLE_LOCK  7
+#define QCOM_MUTEX_NUM_LOCKS   32
+
+static inline u32 __qcom_get_proc_id(struct hwspinlock *lock)
+{
+   return hwspin_lock_get_id(lock) == QCOM_CPUIDLE_LOCK ?
+   (QCOM_MUTEX_CPUIDLE_OFFSET + smp_processor_id()) :
+   QCOM_MUTEX_APPS_PROC_ID;
+}
 
 static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
 {
struct regmap_field *field = lock-priv;
u32 lock_owner;
int ret;
+   u32 proc_id = __qcom_get_proc_id(lock);
 
-   ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
+   ret = regmap_field_write(field, proc_id);
if (ret)
return ret;
 
@@ -42,7 +52,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
if (ret)
return ret;
 
-   return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
+   return lock_owner == proc_id;
 }
 
 static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
@@ -57,7 +67,7 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
return;
}
 
-   if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) {
+   if (lock_owner != __qcom_get_proc_id(lock)) {
pr_err(%s: spinlock not owned by us (actual owner is %d)\n,
__func__, lock_owner);
}
@@ -129,6 +139,8 @@ static int qcom_hwspinlock_probe(struct platform_device 
*pdev)
 regmap, field);
}
 
+   bank-lock[QCOM_CPUIDLE_LOCK].hwcaps = HWL_CAP_ALLOW_RAW;
+
pm_runtime_enable(pdev-dev);
 
ret = hwspin_lock_register(bank, pdev-dev, qcom_hwspinlock_ops,
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [GIT PULL] qcom SoC changes for 4.2-1

2015-06-04 Thread Lina Iyer

On Mon, Jun 01 2015 at 13:13 -0600, Lina Iyer wrote:

On Mon, Jun 01 2015 at 13:04 -0600, Kumar Gala wrote:



On Jun 1, 2015, at 1:35 PM, Arnd Bergmann a...@arndb.de wrote:

On Friday 29 May 2015 14:42:01 Arnd Bergmann wrote:

On Thursday 28 May 2015 10:55:39 Kumar Gala wrote:

Qualcomm ARM Based SoC Updates for v4.2-1

* Added Subsystem Power Manager (SPM) driver
* Split out 32-bit specific SCM code
* Added HDCP SCM call




Pulled into next/drivers, thanks!



I've had to apply this patch on top of our for-next branch to make it
build for randconfig.

Can you check that this makes sense?

Arnd


The QCOM_SCM makes sense, Lina can comment on the ARM_CPU_SUSPEND bit, but 
seems reasonable to me.


Make sense to have both the selects below.

I will test it and report.


I dont see a problem with these changes.


Thanks,
Lina


- k



diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5eea374c8fa6..01aa2fd3514d 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -13,6 +13,8 @@ config QCOM_GSBI
config QCOM_PM
bool Qualcomm Power Management
depends on ARCH_QCOM  !ARM64
+   select QCOM_SCM
+   select ARM_CPU_SUSPEND
help
  QCOM Platform specific power driver to manage cores and L2 low power
  modes. It interface with various system drivers to put the cores in

--
To unsubscribe from this list: send the line unsubscribe linux-arm-msm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 2/2] soc: qcom: spm: Fix idle on THUMB2 kernels

2015-06-04 Thread Lina Iyer

On Tue, Jun 02 2015 at 13:13 -0600, Stephen Boyd wrote:

The ifc6410 firmware always enters the kernel in ARM state from
deep idle. Use the cpu_resume_arm() wrapper instead of
cpu_resume() to property switch into the THUMB2 state when we
wake up from idle.

This fixes a problem reported by Kevin Hilman on next-20150601
where the ifc6410 fails to boot a THUMB2 kernel because the
platform's firmware always enters the kernel in ARM mode from
deep idle states.

Reported-by: Kevin Hilman khil...@linaro.org
Cc: Ard Biesheuvel ard.biesheu...@linaro.org
Cc: Lina Iyer lina.i...@linaro.org
Signed-off-by: Stephen Boyd sb...@codeaurora.org


Reviewd-by: Lina Iyer lina.i...@linaro.org


---
drivers/soc/qcom/spm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b562af816c0a..b04b05a0904e 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -260,7 +260,7 @@ static int __init qcom_cpuidle_init(struct device_node 
*cpu_node, int cpu)
/* We have atleast one power down mode */
cpumask_clear(mask);
cpumask_set_cpu(cpu, mask);
-   qcom_scm_set_warm_boot_addr(cpu_resume, mask);
+   qcom_scm_set_warm_boot_addr(cpu_resume_arm, mask);
}

per_cpu(qcom_idle_ops, cpu) = fns;
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-06-26 Thread Lina Iyer

Hi Ohad,

Any comments?

Thanks,
Lina

On Tue, Jun 09 2015 at 10:23 -0600, Lina Iyer wrote:

This patch follows the discussion based on the first RFC series posted on the
mailing list [1]. The discussion resulted in a couple of directives for
hwspinlocks that do not want the framework imposing a s/w spinlock around the
hwspinlock.

i. The default should only be a s/w spinlock around the hwspinlock to ensure
correctness of locking.

ii. Existing users may not use raw capability, unless the platform registers
support for it.

iii. Platform driver for hwspinlock should dictate which locks can be operated
in raw mode.

iv. Platform driver and the hw holds the responsibility to ensure the
correctness of acquiring the hwspinlock.

This patchset implements these directives.

Changes since RFC v1:
- Introduce 'raw' capability for hwspinlocks.
- Platform code now has to explicitly specify the raw capability of a lock.
- Check to ensure that only those locks explicitly marked as raw capable can be
 locked/unlocked through the _raw api
- QCOM patch for making lock #7 raw capable added.
- Add documentation

Thanks,
Lina

[1]. https://patches.linaro.org/47895/

Lina Iyer (2):
 hwspinlock: Introduce raw capability for hwspinlocks
 hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

Documentation/hwspinlock.txt | 16 +++
drivers/hwspinlock/hwspinlock_core.c | 75 +++-
drivers/hwspinlock/hwspinlock_internal.h |  6 +++
drivers/hwspinlock/qcom_hwspinlock.c | 22 +++---
include/linux/hwspinlock.h   | 41 +
5 files changed, 125 insertions(+), 35 deletions(-)

--
2.1.4


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 2/2] hwspinlock: qcom: Lock #7 is special lock, uses dynamic proc_id

2015-06-10 Thread Lina Iyer

On Wed, Jun 10 2015 at 11:33 -0600, Bjorn Andersson wrote:

On Tue, Jun 9, 2015 at 9:23 AM, Lina Iyer lina.i...@linaro.org wrote:

Hwspinlocks are widely used between processors in an SoC, and also
between elevation levels within in the same processor.  QCOM SoC's use
hwspinlock to serialize entry into a low power mode when the context
switches from Linux to secure monitor.

Lock #7 has been assigned for this purpose. In order to differentiate
between one cpu core holding a lock while another cpu is contending for
the same lock, the proc id written into the lock is (128 + cpu id). This
makes it unique value among the cpu cores and therefore when a core
locks the hwspinlock, other cores would wait for the lock to be released
since they would have a different proc id.  This value is specific for
the lock #7 only.

Declare lock #7 as raw capable, so the hwspinlock framework would not
enfore acquiring a s/w spinlock before acquiring the hwspinlock.



Hi Lina,

Very sorry for slacking off and missing v1 of this.


No worries. Thanks for reviewing.


I'm puzzled to the concept of using the hwspinlock framework for
lock-only locks. The patch your proposed is rather clean and as long
as there's no lock-debugging added to the framework it would work...


Blindly declaring lock #7 as special on all Qualcomm hwspinlocks I do
however not like at all. There's nothing in either the SFPB nor TCSR
mutex hardware that dictates this fact, it's a system configuration
fact. As such this requirement should be described in the device
tree.


Its not a mutable entity, but sure.


The puzzling part of the value to be written is strongly cpuidle
implementation defined makes me wonder if it belong in this driver at
all.

At least this should be configured/flagged by some devicetree
property. qcom,lock-by-cpu-id-locks = 7, ...?


Okay.



The other alternative to these patches would be to just consume the
syscon in cpuidle and opencode the locking there. It isolates the
cpuidle specifics of this to the original place and it isn't using
only one side of the hwspinlock framework...


Well, ultimately a hwspinlock is just a writel, so that is a
possibility, if we want. But it is a hwspinlock, therefore the use of
the framework seems appropriate, even amidst the unique behavior of the
lock.

Thanks,
Lina


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [GIT PULL] qcom SoC changes for 4.2-1

2015-06-01 Thread Lina Iyer

On Mon, Jun 01 2015 at 13:04 -0600, Kumar Gala wrote:



On Jun 1, 2015, at 1:35 PM, Arnd Bergmann a...@arndb.de wrote:

On Friday 29 May 2015 14:42:01 Arnd Bergmann wrote:

On Thursday 28 May 2015 10:55:39 Kumar Gala wrote:

Qualcomm ARM Based SoC Updates for v4.2-1

* Added Subsystem Power Manager (SPM) driver
* Split out 32-bit specific SCM code
* Added HDCP SCM call




Pulled into next/drivers, thanks!



I've had to apply this patch on top of our for-next branch to make it
build for randconfig.

Can you check that this makes sense?

Arnd


The QCOM_SCM makes sense, Lina can comment on the ARM_CPU_SUSPEND bit, but 
seems reasonable to me.


Make sense to have both the selects below.

I will test it and report.

Thanks,
Lina


- k



diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5eea374c8fa6..01aa2fd3514d 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -13,6 +13,8 @@ config QCOM_GSBI
config QCOM_PM
bool Qualcomm Power Management
depends on ARCH_QCOM  !ARM64
+   select QCOM_SCM
+   select ARM_CPU_SUSPEND
help
  QCOM Platform specific power driver to manage cores and L2 low power
  modes. It interface with various system drivers to put the cores in

--
To unsubscribe from this list: send the line unsubscribe linux-arm-msm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-07-02 Thread Lina Iyer

On Sat, Jun 27 2015 at 05:25 -0600, Ohad Ben-Cohen wrote:

Hi Lina,

On Sat, Jun 27, 2015 at 6:05 AM, Lina Iyer lina.i...@linaro.org wrote:

Hi Ohad,

Any comments?


Sorry, I was under the impression the discussion with Bjorn is still open.


I am of the opinion that the platform driver and the framework should
handle this request. This variation is still within the bounds of proper
usage of the hw remote lock. hwspinlock frameowkr imposes a s/w spinlock
around access to every hw remote lock and the current QCOM platform
driver assumes that the value written into the hardware, has to be a
constant.  Both of these are assumptions are the limitations in Linux
and is not a hw remote lock behavior.

I do not agree that the cpuidle driver has to memory map a hwspinlock
region and treat it as a register write, because we dont want to
complicate the hwspinlock platform driver.


Like Bjorn, I'm not so sure too we want to bind a specific lock to the
RAW capability since this is not a lock-specific hardware detail.


You are right, RAW capability is not lock specific. But we dont want to
impose this on every lock in the bank either. Drivers rely on the
framework's s/w spinlock to ensure that different processes in Linux,
trying to lock the same hwspinlock may correctly acquire. The framework
shall guarantee that the hwspinlock is correctly acquired for regular
usecases (where a constant value is written to the h/w t olock). The RAW
capability assumes that the driver acquiring the RAW lock, knows that
the platform will write a unique value to the h/w and therefore the
correctness of locking is assured by the h/w.


As far as I can see, the hardware-specific differences (if any) are at
the vendor level and not at the lock level, therefore it might make
more sense to add the caps member to hwspinlock_device rather than to
the hwspinlock struct (Jeffrey commented about this too).


Jeff's comment is about my commit text pointing to the wrong structure.
I believe he is fine with the implementation. We debated this idea,
before I came up with this patch.

Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC] hwspinlock: Don't take software spinlock before hwspinlock

2015-05-26 Thread Lina Iyer

On Sat, May 23 2015 at 01:36 -0600, Ohad Ben-Cohen wrote:

Hi Lina,

On Mon, May 18, 2015 at 6:03 PM, Lina Iyer lina.i...@linaro.org wrote:

The lock in question is used differently than traditional locks across
processors. This lock helps synchronizes context transition from
non-secure to secure on the same processor.

The usecase, goes like this. In cpuidle, any core can be the last core
to power down. The last man also holds the responsibility of shutting
down shared resources like caches etc. The way the power down of a core
works is, there are some high level decisions made in Linux and these
decisions (like to flush and invalidate caches) etc gets transferred
over to the the secure layer. The secure layer executes the ARM WFI that
powers down the cpu, but uses these decisions passed into to determine
if the cache needs to be invalidated upon wakeup etc.

There is a possible race condition between what Linux thinks is the last
core, vs what secure layer thinks is the last core. Lets say, two cores
c0, c1 are going down. c1 is the second last core to go down from Linux
as such, will not carry information about shared resources when making
the SCM call. c1  made the SCM call, but is stuck handling some FIQs. In
the meanwhile c0, goes idle and since its the last core in Linux,
figures out the state of the shared resources. c0 calls into SCM, and
ends up powering down earlier than c1. Per secure layer, the last core
to go down is c1 and the votes of the shared resources are considered
from that core. Things like cache invalidation without flush may happen
as a result of this inconsistency of last man view point.

The way we have solved it, Linux acquires a hw spinlock for each core,
when calling into SCM and the secure monitor releases the spinlock. At
any given time, only one core can switch the context from Linux to
secure for power down operations. This guarantees the last man is
synchronized between both Linux and secure. Another core may be spinning
waiting for hw mutex, but they all happen serialized. This mutex is held
in an irq disable context in cpuidle.

There may be another processor spining to wait on hw mutex, but there
isnt much to do otherwise, because the only operation at this time while
holding the lock is to call into SCM and that would unlock the mutex.


Just to make sure I understand, is this how your scenario is solved?

- c1 goes down
- c0 goes down, carries information about shared resources
- c1 takes HWLOCK and calls into SCM, stuck handling FIQs
- c0 wants to call into SCM but is waiting spinning on HWLOCK
- c1 completes handling FIQs, goes idle, HWLOCK is released by secure monitor
- c0 takes HWLOCK, calls into SCM, shared resources handled correctly,

HWLOCK in this example is a single shared hwspinlock accessible by c0,
c1 and secure monitor.


That is correct.

-- Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-07-28 Thread Lina Iyer

On Sat, Jul 18 2015 at 05:31 -0600, Ohad Ben-Cohen wrote:

Hi Lina,

On Thu, Jul 2, 2015 at 11:30 PM, Lina Iyer lina.i...@linaro.org wrote:

You are right, RAW capability is not lock specific. But we dont want to
impose this on every lock in the bank either.


I'm not sure I'm following your concern here: drivers still need to
explicitly indicate RAW in order for this to kick in, so this lenient
approach is not being imposed on them.


Correct.


Your original patch allowed every driver on all platforms to disable
the sw spinlock mechanism. What I'm merely suggesting is that the
underlying platform-specific driver should first allow this before it
is being used, as some vendors prohibit this completely.


Agreed. Thats why the platform driver specifies the capability in hwcaps
flag.


Let's not make this more complicated than needed, so please add the
hwcaps member to hwspinlock_device instead of to hwspinlock struct. We
could always change this later if it proves to be insufficient.


But this could yield wrong locking scenarios. If banks are allowed RAW
capability and is not enforced on a per-lock basis, a driver may lock
using non-raw lock using the _raw API, while another driver may
'acquire' the lock (since the value written to the lock would be the
same as raw api would). That is why you should have the capability on
hwspinlock and not on hwspinlock_device. Locks that are defined are RAW
capable should be used as RAW only.

QCOM platform hwlock #7 is unique that different CPUs trying to acquire
the lock would write different values and hence would be fine. But, the
same is not true for other locks in the bank.

Please let me know if this is not clear.

Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-08-14 Thread Lina Iyer

On Fri, Aug 14 2015 at 04:52 -0600, Ohad Ben-Cohen wrote:

On Thu, Aug 13, 2015 at 6:25 PM, Andy Gross agr...@codeaurora.org wrote:

The issue in hardwiring this into the driver itself means forfeiting
extensibility.  So on one side (w/ raw support), we get the ability to deal with
the lock number changing.  On the other side (w/o raw), we'd have to probably
tie this to chip compat to figure out which lock is the 'special' if it ever
changes.


It sounds like the decision which lock to use is a separate problem
from can it go raw.


Absolutely.


If the hardware doesn't prohibit raw mode, then every lock can be used
in raw mode. So you just have to pick one and make sure both sides
know which lock you use --- which is a classic multi-processor
synchronization issue.


It's arbitrary right now.  The remote processor selected a number, not the
processor running Linux.


Is the number hardcoded right now? and you're using
hwspin_lock_request_specific on the Linux side to acquire the lock?


Yes, the number is hardcoded in the SPM power controller driver. It
explicitly requests Lock #7

-- Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH RFC v2 0/2] hwspinlock: Introduce raw capability for hwspinlock_device

2015-08-14 Thread Lina Iyer

On Thu, Aug 13 2015 at 00:34 -0600, Ohad Ben-Cohen wrote:

On Wed, Jul 29, 2015 at 12:51 AM, Lina Iyer lina.i...@linaro.org wrote:

Let's not make this more complicated than needed, so please add the
hwcaps member to hwspinlock_device instead of to hwspinlock struct. We
could always change this later if it proves to be insufficient.


But this could yield wrong locking scenarios. If banks are allowed RAW
capability and is not enforced on a per-lock basis, a driver may lock
using non-raw lock using the _raw API, while another driver may
'acquire' the lock (since the value written to the lock would be the
same as raw api would). That is why you should have the capability on
hwspinlock and not on hwspinlock_device. Locks that are defined are RAW
capable should be used as RAW only.

QCOM platform hwlock #7 is unique that different CPUs trying to acquire
the lock would write different values and hence would be fine. But, the
same is not true for other locks in the bank.


As far as I understand, there is nothing special about QCOM's hwlock
#7 in terms of hardware. It's exactly the same lock as all the others.

The only difference in hwlock #7 is the way you use it, and that
sounds like a decision the driver should be able to make. It's a
policy, and I'm not sure we should put it in the DT. I'm also not sure
we need this hwlock-specific complexity in the hwspinlock framework.


The way I see it, we made a design assumption that all hwspinlocks would
need a s/w spinlock around it. The lock #7 here challenges that
assumption. The framework imposes a s/w lock and it is only appropriate
that the framework provide an option to overcome that.

The hwspinlock bank is just a way to initalize a set of locks in a SoC.
Nobody needs the bank after that. Drivers access locks individually. It
only seems appropriate that the raw be a property of the lock access.


The driver already makes a decision whether to disable the interrupts
or not and whether to save their state or not. So it can also make a
decision whether to take a sw spinlock at all or not --- if the
hardware allows it. and that if should be encoded in an accessible
vendor specific (not hwlock specific) struct, which is setup by the
underlying vendor specific hwspinlock driver (no DT involved).


Would you rather query the hwspinlock driver to see if the framework
should take a s/w spinlock or not, IOW, raw-accessible or not?
That could work.
Every time we call into the raw access API, the framework could query
the hwspinlock driver and then bail out if the hwlock is not raw
accessible.


Let's go over your aforementioned concerns:

But this could yield wrong locking scenarios. If banks are allowed RAW
capability and is not enforced on a per-lock basis, a driver may lock
using non-raw lock using the _raw API


If this is allowed by the hardware, then this is a valid scenario.
There's no such thing a non-raw lock: a lock is raw if a raw
functionality is required.


Agreed. I believe, we are saying the same thing.
A raw access is a request from the calling driver. It is a request from
the driver to directly talk to its hwspinlock driver, without any
encumberance from the framework.


while another driver may
'acquire' the lock (since the value written to the lock would be the
same as raw api would).


Not sure I understand this one. If a lock has already been assigned to
a driver, it cannot be re-assigned to another driver.


Nevermind, not a good example.

Thanks,
Lina
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC v2 5/6] arm: cpuidle: let genpd handle the cluster power transition with 'power-states'

2015-11-11 Thread Lina Iyer

On Wed, Nov 11 2015 at 02:10 -0700, Zhaoyang Huang wrote:

On 6 October 2015 at 22:27, Marc Titinger  wrote:

From: Marc Titinger 

Cpuidle now handles c-states and power-states differently. c-states do not 
decrement
 the reference count for the CPUs in the cluster, while power-states i.e.
cluster level states like 'CLUSTER_SLEEP_0' in the case of juno, will.

The 'D1' fake device also registers intermediate power-state,
for experimentation.

Signed-off-by: Marc Titinger 
---
 arch/arm64/boot/dts/arm/juno.dts |  2 +-
 drivers/cpuidle/cpuidle-arm.c| 52 
 2 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index cadc5de..0bb0dd7 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -47,7 +47,7 @@
};

CLUSTER_SLEEP_0: cluster-sleep-0 {
-   compatible = "arm,idle-state","arm,power-state";
+   compatible = "arm,power-state";
arm,psci-suspend-param = <0x101>;
local-timer-stop;
entry-latency-us = <800>;
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 7c791f9..8dd5dc3 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -40,7 +40,6 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int idx)
 {
int ret;
-   struct device *cpu_dev = get_cpu_device(dev->cpu);

if (!idx) {
cpu_do_idle();
@@ -50,18 +49,49 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
ret = cpu_pm_enter();
if (!ret) {
/*
-* Notify runtime PM as well of this cpu powering down
-* TODO: Merge CPU_PM and runtime PM.
-*/
-   RCU_NONIDLE(pm_runtime_put_sync(cpu_dev));
-
-   /*
 * Pass idle state index to cpu_suspend which in turn will
 * call the CPU ops suspend protocol with idle index as a
 * parameter.
 */
arm_cpuidle_suspend(idx);

+   cpu_pm_exit();
+   }
+
+   return ret ? -1 : idx;
+}
+
+/*
+ * arm_enter_power_state - delegate state trasition to genpd
+ *
+ * dev: cpuidle device
+ * drv: cpuidle driver
+ * idx: state index
+ *
+ * Called from the CPUidle framework to delegate a state transition
+ * to the generic domain. This will be a cluster poweroff state
+ * the Domain will chose to actually turn off the cluster based on
+ * the status of other CPUs, and devices and subdomains in the Cluster
+ * domain.
+*/
+static int arm_enter_power_state(struct cpuidle_device *dev,
+   struct cpuidle_driver *drv, int idx)
+{
+   int ret;
+   struct device *cpu_dev = get_cpu_device(dev->cpu);
+
+   BUG_ON(idx == 0);
+
+   ret = cpu_pm_enter();
+   if (!ret) {
+   /*
+   * Notify runtime PM as well of this cpu powering down
+   * TODO: Merge CPU_PM and runtime PM.
+   */
+   RCU_NONIDLE(pm_runtime_put_sync(cpu_dev));

[question]: Does it mean that above function will use the gpd->rpm->idle?


Will end up at rpm_suspend() in runtime.c which will callinto genpd. Its
not a direct call to genpd.

Thanks,
Lina


+
+   arm_cpuidle_suspend(idx);
+
RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
cpu_pm_exit();
}
@@ -69,6 +99,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
return ret ? -1 : idx;
 }

+
 static struct cpuidle_driver arm_idle_driver = {
.name = "arm_idle",
.owner = THIS_MODULE,
@@ -90,9 +121,10 @@ static struct cpuidle_driver arm_idle_driver = {
 };

 static const struct of_device_id arm_idle_state_match[] __initconst = {
-   { .compatible = "arm,idle-state",
- .data = arm_enter_idle_state },
-   { },
+   {.compatible = "arm,idle-state",
+.data = arm_enter_idle_state},
+   {.compatible = "arm,power-state",
+.data = arm_enter_power_state},
 };

 /*
--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC v2 2/6] PM / Domains: prepare for devices that might register a power state

2015-10-08 Thread Lina Iyer

Hi Marc,

Thanks for rebasing on top of my latest series.

On Tue, Oct 06 2015 at 08:27 -0600, Marc Titinger wrote:

Devices may register an intermediate retention state into the domain upon


I may agree with the usability of dynamic adding a state to the domain,
but I dont see why a device attaching to a domain should bring about a
new domain state.

A domain should define its power states, independent of the devices that
may attach. The way I see it, devices have their own idle states and
domains have their own. I do see a relationship between possible domain
states depending on the states of the individual devices in the domain.
For ex, a CPU domain can only be in a retention state (low voltage,
memory retained), if its CPU devices are in retention state, i.e, the
domain cannot be powered off; alternately, the domain may be in
retention or power down if the CPU devices are in power down state.

Could you elaborate on why this is a need?

Thanks,
Lina


attaching. Currently generic domain would register an array of states upon
init. This patch prepares for later insertion (sort per depth, remove).

Signed-off-by: Marc Titinger 
---
drivers/base/power/domain.c | 189 +++-
include/linux/pm_domain.h   |  18 -
2 files changed, 97 insertions(+), 110 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3e27a2b..e5f4c00b 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -19,6 +19,7 @@
#include 
#include 
#include 
+#include 

#define GENPD_RETRY_MAX_MS  250 /* Approximate */

@@ -50,12 +51,6 @@
__retval;   
\
})

-#define GENPD_MAX_NAME_SIZE 20
-
-static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
-  const struct genpd_power_state *st,
-  unsigned int st_count);
-
static LIST_HEAD(gpd_list);
static DEFINE_MUTEX(gpd_list_lock);

@@ -1364,46 +1359,6 @@ static void genpd_free_dev_data(struct device *dev,
dev_pm_put_subsys_data(dev);
}

-static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
-  const struct genpd_power_state *st,
-  unsigned int st_count)
-{
-   int ret = 0;
-   unsigned int i;
-
-   if (IS_ERR_OR_NULL(genpd)) {
-   ret = -EINVAL;
-   goto err;
-   }
-
-   if (!st || (st_count < 1)) {
-   ret = -EINVAL;
-   goto err;
-   }
-
-   /* Allocate the local memory to keep the states for this genpd */
-   genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
-   if (!genpd->states) {
-   ret = -ENOMEM;
-   goto err;
-   }
-
-   for (i = 0; i < st_count; i++) {
-   genpd->states[i].power_on_latency_ns =
-   st[i].power_on_latency_ns;
-   genpd->states[i].power_off_latency_ns =
-   st[i].power_off_latency_ns;
-   }
-
-   genpd->state_count = st_count;
-
-   /* to save memory, Name allocation will happen if debug is enabled */
-   pm_genpd_alloc_states_names(genpd, st, st_count);
-
-err:
-   return ret;
-}
-
/**
 * __pm_genpd_add_device - Add a device to an I/O PM domain.
 * @genpd: PM domain to add the device to.
@@ -1833,6 +1788,75 @@ static void genpd_lock_init(struct generic_pm_domain 
*genpd)
}
}

+
+/*
+* state depth comparison function.
+*/
+static int state_cmp(const void *a, const void *b)
+{
+   struct genpd_power_state *state_a = (struct genpd_power_state *)(a);
+   struct genpd_power_state *state_b = (struct genpd_power_state *)(b);
+
+   s64 depth_a =
+   state_a->power_on_latency_ns + state_a->power_off_latency_ns;
+   s64 depth_b =
+   state_b->power_on_latency_ns + state_b->power_off_latency_ns;
+
+   return (depth_a > depth_b) ? 0 : -1;
+}
+
+/*
+* TODO: antagonist routine.
+*/
+int pm_genpd_insert_state(struct generic_pm_domain *genpd,
+   const struct genpd_power_state *state)
+{
+   int ret = 0;
+   int state_count = genpd->state_count;
+
+   if (IS_ERR_OR_NULL(genpd) || (!state))
+   ret = -EINVAL;
+
+   if (state_count >= GENPD_POWER_STATES_MAX)
+   ret = -ENOMEM;
+
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+   /* to save memory, Name allocation will happen if debug is enabled */
+   genpd->states[state_count].name = kstrndup(state->name,
+   GENPD_MAX_NAME_SIZE,
+   GFP_KERNEL);
+   if (!genpd->states[state_count].name) {
+   pr_err("%s Failed to allocate state '%s' name.\n",
+   genpd->name, state->name);
+   ret = -ENOMEM;
+   }
+#endif
+   genpd_lock(genpd);
+
+   if (!ret) {
+   

Re: [RFC v2 3/6] PM / Domains: introduce power-states consistent with c-states.

2015-10-08 Thread Lina Iyer

On Tue, Oct 06 2015 at 08:27 -0600, Marc Titinger wrote:

This patch allows cluster-level C-states to being soaked in as generic
domain power states, in order for the domain governor to chose the most
efficient power state compatible with the device constraints. Similarly,
devices can register power-states into the cluster domain, in a manner
consistent with c-states.


A domain power state as depicted in the DT is no different than the CPU
idle state. I think you can achieve this without adding another
compatible - arm,power-state.

I think I am still at loss trying to understand why a device is
populating the domain's power states.


With Juno, in this example the c-state 'cluster-sleep-0 ' is known from
each cluster generic domain, as the deepest sate.

cat /sys/kernel/debug/pm_genpd/*

 Domain State nameEnter (ns) / Exit (ns)
-
a53_pd   cluster-sleep-0  150 / 80
a57_pd   cluster-sleep-0  150 / 80

   domain  status pstate slaves
  /device  runtime status
---
a53_pd  on
   /devices/system/cpu/cpu0active
   /devices/system/cpu/cpu3suspended
   /devices/system/cpu/cpu4suspended
   /devices/system/cpu/cpu5suspended
   /devices/platform/D1suspended
a57_pd  cluster-sleep-0
   /devices/system/cpu/cpu1suspended
   /devices/system/cpu/cpu2suspended

Signed-off-by: Marc Titinger 
---
.../devicetree/bindings/arm/idle-states.txt|  21 -
.../devicetree/bindings/power/power_domain.txt |  29 ++
arch/arm64/boot/dts/arm/juno.dts   |  10 ++-
drivers/base/power/cpu-pd.c|   5 ++
drivers/base/power/domain.c| 100 +
include/linux/pm_domain.h  |   3 +
6 files changed, 163 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt 
b/Documentation/devicetree/bindings/arm/idle-states.txt
index a8274ea..18fdeaf 100644
--- a/Documentation/devicetree/bindings/arm/idle-states.txt
+++ b/Documentation/devicetree/bindings/arm/idle-states.txt
@@ -270,7 +270,8 @@ follows:
- compatible
Usage: Required
Value type: 
-   Definition: Must be "arm,idle-state".
+   Definition: Must be "arm,idle-state",
+   or "arm,power-state" (see section 5)

- local-timer-stop
Usage: See definition
@@ -680,7 +681,23 @@ cpus {
};

===
-5 - References
+5 - power state
+===
+
+Device in a generic power domain may expose an intermediate retention
+state that can be opted to by the domain governor when the last-man
+CPU is powered off. Those power-states will not be entered by the
+cpuidle.ops based on a state index, but instead can be elected by the
+domain governor and entered to by the generic domain.
+

Agreed.


+ - compatible
+Usage: Required
+Value type: 
+Definition: Must be "arm,power-state".
+
+
+===
+6 - References
===

[1] ARM Linux Kernel documentation - CPUs bindings
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt 
b/Documentation/devicetree/bindings/power/power_domain.txt
index 0f8ed37..d437385 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -29,6 +29,16 @@ Optional properties:
   specified by this binding. More details about power domain specifier are
   available in the next section.

+ - power-states : a phandle of an idle-state that shall be soaked into a
+ generic domain power state.
+   CPU domains: Deep c-states that match a cluster power-off can be delegated 
to the
+   generic power domain. Device other than CPUs may have register intermediate
+   power states in the same domain. The domain governor can do a good job in
+   electing a power state when the last cpu is powered off as devices in the
+   same genpd may register intermediate states.


Devices may enable a certain domain state, but should not be defining
the domain state. The domain its state and the domain governor may
choose to enter that state on a vote from its devices.


+   Devices : a device may register an intermediate c-state matching a memory
+   retention feature for instance.


This point onwards is where I need clarity.

Thanks,
Lina


Re: [RFC v2 0/6] Managing cluser-level c-states with generic power domains

2015-10-19 Thread Lina Iyer

Hi Marc,

I am trying to apply this on top of Axel's patches on linux-next (after
fixing issues I saw with his v9), and running to issues applying your
patches. Could you rebase on top of his v10 (he said he would send to
the ML soon) ?

Thanks,
Lina

On Tue, Oct 06 2015 at 08:27 -0600, Marc Titinger wrote:

v2:
- rebase on Lina Iyer's latest series
- remove unnecessary dependency on perf-state patches from Axel Haslam

---

Summary

1) DESCRIPTION
2) DEPENDENCIES
3) URL



1) DESCRIPTION


This patch set's underlying idea is that cluster-level c-states can be 
managed
by the power domain, building upon Lina Iyers recent work on CPU-domain, and 
Axel Haslam's
genpd multiple states. The power domain may contain CPU devices and non-CPU 
devices.

Non-CPU Devices may expose latency constraints by registering intermediate 
power-states upon
probing, for instance shallower states than the deepest cluster-off state. The 
generic
power domain governor may chose a device retention state in place of the 
cluster-sleep
state demanded by the menu governor, and call the platform specific handling to 
enter/leave
that retention state.


power-states
---


The proposed way how cluster-level c-states are declared as manageable by the
power domain, rather than through the cpuidle-ops, relies on the introduction of
"power-states", consistent with c-states. Here is an example of the DT bindings,
the c-state CLUSTER_SLEEP_0 is exposed as a power-state in the compatible 
property:

juno.dts:   idle-states {
   entry-method = "arm,psci";

   CPU_SLEEP_0: cpu-sleep-0 {
   compatible = "arm,idle-state";
   arm,psci-suspend-param = <0x001>;
   local-timer-stop;
   entry-latency-us = <100>;
   exit-latency-us = <250>;
   min-residency-us = <2000>;
   };

   CLUSTER_SLEEP_0: cluster-sleep-0 {
   compatible = "arm,power-state";
   arm,psci-suspend-param = <0x101>;
   local-timer-stop;
   entry-latency-us = <800>;
   exit-latency-us = <700>;
   min-residency-us = <2500>;
   };
}

This will tell cpuidle runtime_put/get the CPU devices for this c-state. 
Eventually, the
actual platform handlers may be called from the genpd platform ops (in place of 
cpuidle_ops).

"drivers/cpuidle/cpuidle-arm.c":

static const struct of_device_id arm_idle_state_match[] __initconst = {
   {.compatible = "arm,idle-state",
.data = arm_enter_idle_state},
   {.compatible = "arm,power-state",
.data = arm_enter_power_state},
};


In case of a power-state, arm_enter_power_state will only call 
pm_runtime_put/get_sync
The power doamin will handle the power off, currently this patch set lacks the 
final
call to the psci interface to have a fully fonctionnal setup
(and there are some genpd_lock'ing issues if put/get actually suspend the CPU 
device.)

Ultimately, we would like the Power Domain's simple governor to being able to 
chose
the cluster power-state based on the c-states defered to it (power-states) and 
constraints
added by the devices. Consequently, we need to "soak" those power-states into 
the
power-domain intermediate states from Axel. Since power-states are declared and 
handled
the same manner than c-states (idle-states in DT), these patches add a soaking 
used when
attaching to a genpd, where power-states are parsed from the DT into the genpd 
states:


"drivers/base/power/domain.c":

static const struct of_device_id power_state_match[] = {
   {.compatible = "arm,power-state",
},
};

int of_genpd_device_parse_states(struct device_node *np,
struct generic_pm_domain *genpd)

debugfs addition
---

To easy debug, this patch set adds a seq-file names "states" to the pm_genpd 
debugfs:

   cat /sys/kernel/debug/pm_genpd/*

 Domain State nameEnter (ns) / Exit (ns)
   -
   a53_pd   cluster-sleep-0  150 / 80
   a57_pd   cluster-sleep-0  150 / 80

And also a seq-file "timings", to help visualize the constrains of the non-CPU
devices in a cluster PD.

   Domain Devices, Timings in ns
  Stop/Start Save/Restore, Effective
  ---
a57_pd
   /cpus/cpu@0  800   /7401320  /1720  ,0 (cached stop)
   /cpus/cpu@1  800   /7401420  /1780  ,0 (cached stop)
   /D1  660   /58016560 /6080  ,2199420 (cached stop)


Device 

Re: [PATCH v9 1/6] PM / Domains: prepare for multiple states

2015-10-19 Thread Lina Iyer

Hi Axel,

Thanks for rebasing.

I ran into a compilation issue on ARM64 with defconfig.

On Mon, Oct 19 2015 at 08:52 -0600, ahas...@baylibre.com wrote:

From: Axel Haslam <ahaslam+rene...@baylibre.com>

prepare generic power domain init function parameters to accept a pointer
to the states structure that describes the possible states that a power
domain can enter.

Also, as most platforms are not initializing states or latencies, add
pm_genpd_init_simple that allows platfroms to use a default single OFF
state with initial latencies set to 0.

There is no functional change, as support for multiple domains will be
added in subsequent patches.

Suggested-by: Lina Iyer <lina.i...@linaro.org>
Signed-off-by: Axel Haslam <ahaslam+rene...@baylibre.com>
---
arch/arm/mach-exynos/pm_domains.c |  2 +-
arch/arm/mach-imx/gpc.c   |  2 +-
arch/arm/mach-s3c64xx/pm.c|  4 ++--
arch/arm/mach-shmobile/pm-r8a7779.c   |  2 +-
arch/arm/mach-shmobile/pm-rmobile.c   |  2 +-
arch/arm/mach-ux500/pm_domains.c  |  2 +-
arch/arm/mach-zx/zx296702-pm-domain.c |  2 +-
drivers/base/power/domain.c   | 19 ++-
drivers/clk/shmobile/clk-mstp.c   |  2 +-


Change in drivers/clk/qcom/gdsc.c is missing.

Thanks,
Lina


drivers/soc/dove/pmu.c|  2 +-
drivers/soc/mediatek/mtk-scpsys.c |  2 +-
include/linux/pm_domain.h | 27 ++-
12 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-exynos/pm_domains.c 
b/arch/arm/mach-exynos/pm_domains.c
index 4a87e86..a0abaa1 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -187,7 +187,7 @@ static __init int exynos4_pm_init_power_domain(void)
no_clk:
on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN;

-   pm_genpd_init(>pd, NULL, !on);
+   pm_genpd_init_simple(>pd, NULL, !on);
of_genpd_add_provider_simple(np, >pd);
}

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 8c4467f..76658f8 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -419,7 +419,7 @@ static int imx_gpc_genpd_init(struct device *dev, struct 
regulator *pu_reg)
if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
return 0;

-   pm_genpd_init(_pu_domain.base, NULL, false);
+   pm_genpd_init_simple(_pu_domain.base, NULL, false);
return of_genpd_add_provider_onecell(dev->of_node,
 _gpc_onecell_data);

diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index 75b14e7..d68a45c 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -316,11 +316,11 @@ int __init s3c64xx_pm_init(void)
s3c_pm_init();

for (i = 0; i < ARRAY_SIZE(s3c64xx_always_on_pm_domains); i++)
-   pm_genpd_init(_always_on_pm_domains[i]->pd,
+   pm_genpd_init_simple(_always_on_pm_domains[i]->pd,
  _domain_always_on_gov, false);

for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++)
-   pm_genpd_init(_pm_domains[i]->pd, NULL, false);
+   pm_genpd_init_simple(_pm_domains[i]->pd, NULL, false);

#ifdef CONFIG_S3C_DEV_FB
if (dev_get_platdata(_device_fb.dev))
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c 
b/arch/arm/mach-shmobile/pm-r8a7779.c
index 47a862e..5eac8cd 100644
--- a/arch/arm/mach-shmobile/pm-r8a7779.c
+++ b/arch/arm/mach-shmobile/pm-r8a7779.c
@@ -84,7 +84,7 @@ static void r8a7779_init_pm_domain(struct r8a7779_pm_domain 
*r8a7779_pd)
{
struct generic_pm_domain *genpd = _pd->genpd;

-   pm_genpd_init(genpd, NULL, false);
+   pm_genpd_init_simple(genpd, NULL, false);
genpd->dev_ops.active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c 
b/arch/arm/mach-shmobile/pm-rmobile.c
index a5b96b9..e1ca6e2 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -160,7 +160,7 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain 
*rmobile_pd)
struct dev_power_governor *gov = rmobile_pd->gov;

genpd->flags = GENPD_FLAG_PM_CLK;
-   pm_genpd_init(genpd, gov ? : _qos_governor, false);
+   pm_genpd_init_simple(genpd, gov ? : _qos_governor, false);
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
genpd->power_off = rmobile_pd_power_down;
genpd->power_on  = rmobile_pd_power_up;
diff --git a/arch/arm/mach-ux500/pm_domains.c b/arch/arm/mach-ux500/pm_domains.c
index 4d71c90..208e784 100644
--- a/arch/arm/mach-ux500/pm_domains.c
+++ b/arch/arm/mach-ux500/pm_domains.c
@@ -72,7 +72,7 @@ int __init ux500_pm_domains_init(void)
genpd_data->num_domains = ARR

Re: [RFC v2 2/6] PM / Domains: prepare for devices that might register a power state

2015-10-09 Thread Lina Iyer

On Fri, Oct 09 2015 at 03:39 -0600, Marc Titinger wrote:

On 08/10/2015 18:11, Lina Iyer wrote:

Hi Marc,

Thanks for rebasing on top of my latest series.

On Tue, Oct 06 2015 at 08:27 -0600, Marc Titinger wrote:

Devices may register an intermediate retention state into the domain upon


I may agree with the usability of dynamic adding a state to the domain,
but I dont see why a device attaching to a domain should bring about a
new domain state.


Hi Lina,

thanks a lot for taking the time to look into this. The initial 
discussion behind it was about to see how a device like a PMU, FPU, 
cache, or a Healthcheck IP in the same power domain than CPUs, with 
special retention states can be handled in a way 'unified' with CPUs.
Also I admit it is partly an attempt from us to create something 
useful out of the "collision" of Axel's multiple states and your 
CPUs-as-generic-power-domain-devices, hence the RFC!


Looking at Juno for instance, she currently has a platform-initiated 
mode implemented in the arm-trusted-firmware through psci as a 
cpuidle-driver. the menu governor will select a possibly deep c-state, 
but the last-man CPU and actual power state is known to ATF. Similarly 
my idea was to have a genpd-initiated mode so to say, where the actual 
power state results from the cpu-domain's governor choice based on 
possible retention states, and their latency.



Okay, I must admit that my ideas are quite partial to OS-initiated PSCI
(v1.0 onwards). So you have C-States that allow domains to enter idle as
well. Fair.

A Health-check IP or Cache will not (to my current knowledge) have a 
driver calling runtime_put, but may have a retention state "D1_RET" 
with a off/on latency between CPU_SLEEP and CLUSTER_SLEEP, so that 
CLUSTER_SLEEP may be ruled out by the governor, but D1_RET is ok given 
the time slot available. 


A couple of questions here.

You say there is no driver for HIP, is there a device for it atleast?
How is the CPU/Domain going to know if the HIP is running or not?

To me this seems like you want to set a QoS on the PM domain here.

Some platform code can be called so that the 
cluster goes to D1_RET in that case, upon the last-man CPU 
waiting-for-interrupt. Note that in the case of a Health-Check HIP, 
the state my actually be a working state (all CPUs power down, and 
time slot OK for sampling stuff).



Building on my previous statement, if you have a QoS for a domain and a
domain governor, it could consider the QoS requirement and choose to do
retention. However that needs a driver or some entity that know the HIP
is requesting a D1_RET mode only.



A domain should define its power states, independent of the devices that
may attach. The way I see it, devices have their own idle states and
domains have their own. I do see a relationship between possible domain
states depending on the states of the individual devices in the domain.
For ex, a CPU domain can only be in a retention state (low voltage,
memory retained), if its CPU devices are in retention state, i.e, the
domain cannot be powered off; alternately, the domain may be in
retention or power down if the CPU devices are in power down state.

Could you elaborate on why this is a need?


Well, it may not be a need TBH, it is an attempt to have cluster-level 
devices act like hotplugged CPUs but with heterogeneous c-states and 
latencies. I hope it makes some sense :)



Hmm.. Let me think about it.

What would be a difference between a cluster-level device and a CPU in
the same domain?

-- Lina


Thanks,
Marc.




Thanks,
Lina


attaching. Currently generic domain would register an array of states
upon
init. This patch prepares for later insertion (sort per depth, remove).

Signed-off-by: Marc Titinger <mtitinger+rene...@baylibre.com>
---
drivers/base/power/domain.c | 189
+++-
include/linux/pm_domain.h   |  18 -
2 files changed, 97 insertions(+), 110 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3e27a2b..e5f4c00b 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -19,6 +19,7 @@
#include 
#include 
#include 
+#include 

#define GENPD_RETRY_MAX_MS250/* Approximate */

@@ -50,12 +51,6 @@
   __retval;\
})

-#define GENPD_MAX_NAME_SIZE 20
-
-static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
-   const struct genpd_power_state *st,
-   unsigned int st_count);
-
static LIST_HEAD(gpd_list);
static DEFINE_MUTEX(gpd_list_lock);

@@ -1364,46 +1359,6 @@ static void genpd_free_dev_data(struct device
*dev,
   dev_pm_put_subsys_data(dev);
}

-static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
-   const struct genpd_power_state *st,
-   unsigned int st_count)
-{
-int ret = 0;
-unsigned int i;
-
-if (IS_ERR_OR_NULL(genpd)) {
-ret = 

Re: [PATCH v3 2/3] ARM: cpuidle: refine cpuidle_ops member's parameters.

2015-07-10 Thread Lina Iyer

On Thu, Jul 09 2015 at 03:28 -0600, Lorenzo Pieralisi wrote:

On Thu, Jul 09, 2015 at 09:43:04AM +0100, Jisheng Zhang wrote:

On Thu, 9 Jul 2015 16:31:24 +0800
Jisheng Zhang jszh...@marvell.com wrote:

 As for the suspend member function, the to-be-suspended cpu is always
 the calling cpu itself, so the 'cpu' parameter may not be necessary, let
 driver get 'cpu' itself if need.

 As for the init member function, the device_node here may not be
 necessary either, because we can get the node via. of_get_cpu_node().

This patch also changes drivers/soc/qcom/spm.c accordingly, but I have no
qcom platform, so I can't test it, just make sure it can pass kernel building.
Could anyone kindly help me to test?


CC'ing Lina who should be able to help you test it.


Sure, will test and let you know.

-- Lina


Thanks,
Lorenzo


Thanks a lot,
Jisheng


 Signed-off-by: Jisheng Zhang jszh...@marvell.com
 ---
  arch/arm/include/asm/cpuidle.h |  6 +++---
  arch/arm/kernel/cpuidle.c  |  8 
  drivers/soc/qcom/spm.c | 17 -
  3 files changed, 19 insertions(+), 12 deletions(-)

 diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
 index 0f84249..ca5dfe6 100644
 --- a/arch/arm/include/asm/cpuidle.h
 +++ b/arch/arm/include/asm/cpuidle.h
 @@ -30,8 +30,8 @@ static inline int arm_cpuidle_simple_enter(struct 
cpuidle_device *dev,
  struct device_node;

  struct cpuidle_ops {
 -  int (*suspend)(int cpu, unsigned long arg);
 -  int (*init)(struct device_node *, int cpu);
 +  int (*suspend)(unsigned long arg);
 +  int (*init)(unsigned int cpu);
  };

  struct of_cpuidle_method {
 @@ -46,6 +46,6 @@ struct of_cpuidle_method {

  extern int arm_cpuidle_suspend(int index);

 -extern int arm_cpuidle_init(int cpu);
 +extern int arm_cpuidle_init(unsigned int cpu);

  #endif
 diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
 index 318da33..7bc7bc6 100644
 --- a/arch/arm/kernel/cpuidle.c
 +++ b/arch/arm/kernel/cpuidle.c
 @@ -53,10 +53,10 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
  int arm_cpuidle_suspend(int index)
  {
int ret = -EOPNOTSUPP;
 -  int cpu = smp_processor_id();
 +  unsigned int cpu = smp_processor_id();

if (cpuidle_ops[cpu].suspend)
 -  ret = cpuidle_ops[cpu].suspend(cpu, index);
 +  ret = cpuidle_ops[cpu].suspend(index);

return ret;
  }
 @@ -134,7 +134,7 @@ static int __init arm_cpuidle_read_ops(struct device_node 
*dn, int cpu)
   *  -ENXIO if the HW reports a failure or a misconfiguration,
   *  -ENOMEM if the HW report an memory allocation failure
   */
 -int __init arm_cpuidle_init(int cpu)
 +int __init arm_cpuidle_init(unsigned int cpu)
  {
struct device_node *cpu_node = of_cpu_device_node_get(cpu);
int ret;
 @@ -144,7 +144,7 @@ int __init arm_cpuidle_init(int cpu)

ret = arm_cpuidle_read_ops(cpu_node, cpu);
if (!ret  cpuidle_ops[cpu].init)
 -  ret = cpuidle_ops[cpu].init(cpu_node, cpu);
 +  ret = cpuidle_ops[cpu].init(cpu);

of_node_put(cpu_node);

 diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
 index b04b05a..1649ec3 100644
 --- a/drivers/soc/qcom/spm.c
 +++ b/drivers/soc/qcom/spm.c
 @@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {

  static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);

 -typedef int (*idle_fn)(int);
 +typedef int (*idle_fn)(void);
  static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);

  static inline void spm_register_write(struct spm_driver_data *drv,
 @@ -179,9 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
return -1;
  }

 -static int qcom_cpu_spc(int cpu)
 +static int qcom_cpu_spc(void)
  {
int ret;
 +  int cpu = smp_processor_id();
struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);

spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
 @@ -197,9 +198,11 @@ static int qcom_cpu_spc(int cpu)
return ret;
  }

 -static int qcom_idle_enter(int cpu, unsigned long index)
 +static int qcom_idle_enter(unsigned long index)
  {
 -  return per_cpu(qcom_idle_ops, cpu)[index](cpu);
 +  unsigned int cpu = smp_processor_id();
 +
 +  return per_cpu(qcom_idle_ops, cpu)[index]();
  }

  static const struct of_device_id qcom_idle_state_match[] __initconst = {
 @@ -207,7 +210,7 @@ static const struct of_device_id qcom_idle_state_match[] 
__initconst = {
{ },
  };

 -static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
 +static int __init qcom_cpuidle_init(unsigned int cpu)
  {
const struct of_device_id *match_id;
struct device_node *state_node;
 @@ -217,6 +220,10 @@ static int __init qcom_cpuidle_init(struct device_node 
*cpu_node, int cpu)
idle_fn *fns;
cpumask_t mask;
bool use_scm_power_down = false;
 +  struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
 +
 +  if (!cpu_node)
 +  return -ENODEV;

for (i = 0; ; i++) {
state_node = of_parse_phandle(cpu_node, cpu-idle-states, i);


--
To unsubscribe 

Re: [PATCH v3 2/3] ARM: cpuidle: refine cpuidle_ops member's parameters.

2015-07-10 Thread Lina Iyer

On Thu, Jul 09 2015 at 02:33 -0600, Jisheng Zhang wrote:

As for the suspend member function, the to-be-suspended cpu is always
the calling cpu itself, so the 'cpu' parameter may not be necessary, let
driver get 'cpu' itself if need.

As for the init member function, the device_node here may not be
necessary either, because we can get the node via. of_get_cpu_node().

Signed-off-by: Jisheng Zhang jszh...@marvell.com


Tested-by: Lina Iyer lina.i...@linaro.org


---
arch/arm/include/asm/cpuidle.h |  6 +++---
arch/arm/kernel/cpuidle.c  |  8 
drivers/soc/qcom/spm.c | 17 -
3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 0f84249..ca5dfe6 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -30,8 +30,8 @@ static inline int arm_cpuidle_simple_enter(struct 
cpuidle_device *dev,
struct device_node;

struct cpuidle_ops {
-   int (*suspend)(int cpu, unsigned long arg);
-   int (*init)(struct device_node *, int cpu);
+   int (*suspend)(unsigned long arg);
+   int (*init)(unsigned int cpu);
};

struct of_cpuidle_method {
@@ -46,6 +46,6 @@ struct of_cpuidle_method {

extern int arm_cpuidle_suspend(int index);

-extern int arm_cpuidle_init(int cpu);
+extern int arm_cpuidle_init(unsigned int cpu);

#endif
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
index 318da33..7bc7bc6 100644
--- a/arch/arm/kernel/cpuidle.c
+++ b/arch/arm/kernel/cpuidle.c
@@ -53,10 +53,10 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
int arm_cpuidle_suspend(int index)
{
int ret = -EOPNOTSUPP;
-   int cpu = smp_processor_id();
+   unsigned int cpu = smp_processor_id();

if (cpuidle_ops[cpu].suspend)
-   ret = cpuidle_ops[cpu].suspend(cpu, index);
+   ret = cpuidle_ops[cpu].suspend(index);

return ret;
}
@@ -134,7 +134,7 @@ static int __init arm_cpuidle_read_ops(struct device_node 
*dn, int cpu)
 *  -ENXIO if the HW reports a failure or a misconfiguration,
 *  -ENOMEM if the HW report an memory allocation failure
 */
-int __init arm_cpuidle_init(int cpu)
+int __init arm_cpuidle_init(unsigned int cpu)
{
struct device_node *cpu_node = of_cpu_device_node_get(cpu);
int ret;
@@ -144,7 +144,7 @@ int __init arm_cpuidle_init(int cpu)

ret = arm_cpuidle_read_ops(cpu_node, cpu);
if (!ret  cpuidle_ops[cpu].init)
-   ret = cpuidle_ops[cpu].init(cpu_node, cpu);
+   ret = cpuidle_ops[cpu].init(cpu);

of_node_put(cpu_node);

diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b04b05a..1649ec3 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {

static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);

-typedef int (*idle_fn)(int);
+typedef int (*idle_fn)(void);
static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);

static inline void spm_register_write(struct spm_driver_data *drv,
@@ -179,9 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
return -1;
}

-static int qcom_cpu_spc(int cpu)
+static int qcom_cpu_spc(void)
{
int ret;
+   int cpu = smp_processor_id();
struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);

spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
@@ -197,9 +198,11 @@ static int qcom_cpu_spc(int cpu)
return ret;
}

-static int qcom_idle_enter(int cpu, unsigned long index)
+static int qcom_idle_enter(unsigned long index)
{
-   return per_cpu(qcom_idle_ops, cpu)[index](cpu);
+   unsigned int cpu = smp_processor_id();
+
+   return per_cpu(qcom_idle_ops, cpu)[index]();
}

static const struct of_device_id qcom_idle_state_match[] __initconst = {
@@ -207,7 +210,7 @@ static const struct of_device_id qcom_idle_state_match[] 
__initconst = {
{ },
};

-static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
+static int __init qcom_cpuidle_init(unsigned int cpu)
{
const struct of_device_id *match_id;
struct device_node *state_node;
@@ -217,6 +220,10 @@ static int __init qcom_cpuidle_init(struct device_node 
*cpu_node, int cpu)
idle_fn *fns;
cpumask_t mask;
bool use_scm_power_down = false;
+   struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
+
+   if (!cpu_node)
+   return -ENODEV;

for (i = 0; ; i++) {
state_node = of_parse_phandle(cpu_node, cpu-idle-states, i);
--
2.1.4


___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read

[PATCH] drivers: qcom: Select QCOM_SCM unconditionally for QCOM_PM

2015-07-10 Thread Lina Iyer
Enable QCOM_SCM for QCOM power management driver

Signed-off-by: Lina Iyer lina.i...@linaro.org
---
 drivers/soc/qcom/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5eea374..e9a2c19 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -13,6 +13,7 @@ config QCOM_GSBI
 config QCOM_PM
bool Qualcomm Power Management
depends on ARCH_QCOM  !ARM64
+   select QCOM_SCM
help
  QCOM Platform specific power driver to manage cores and L2 low power
  modes. It interface with various system drivers to put the cores in
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: Build error with !CONFIG_SMP in v4.2-rc1 on arm multi_v7_defconfig

2015-07-10 Thread Lina Iyer

On Fri, Jul 10 2015 at 14:29 -0600, Dave Gerlach wrote:

On 07/10/2015 02:36 PM, Stephen Boyd wrote:

On 07/10/2015 12:31 PM, Dave Gerlach wrote:

Hello,
I am seeing the following error when building v4.2-rc1 for arm with
multi_v7_defconfig with CONFIG_SMP=n:

 LINKvmlinux
  LD  vmlinux.o
  MODPOST vmlinux.o
  GEN .version
  CHK include/generated/compile.h
  UPD include/generated/compile.h
  CC  init/version.o
  LD  init/built-in.o
drivers/built-in.o: In function `qcom_pm_collapse':
:(.text+0xaf44c): undefined reference to `qcom_scm_cpu_power_down'
drivers/built-in.o: In function `qcom_cpuidle_init':
:(.init.text+0x9508): undefined reference to `qcom_scm_set_warm_boot_addr'
make: *** [vmlinux] Error 1


It appears the calling functions in drivers/soc/qcom/spm.c get included by
CONFIG_QCOM_PM which is part of multi_v7_defconfig but the missing functions
from drivers/firmware/qcom_scm.c only get included by CONFIG_QCOM_SCM if SMP is
selected. I am not sure if the correct approach is to remove CONFIG_QCOM_PM from
multi_v7_defconfig or to remove 'if SMP' from CONFIG_QCOM_SCM, or something else
entirely. Thoughts?




CONFIG_QCOM_PM should select CONFIG_QCOM_SCM unconditionally.



Ok thanks, I can send a quick patch.


I sent one a few minutes ago, in reply to your mail :)
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] kernel/cpu_pm: fix cpu_cluster_pm_exit comment

2015-09-02 Thread Lina Iyer
cpu_cluster_pm_exit() must be sent after cpu_cluster_pm_enter() has been
sent for the cluster and before any cpu_pm_exit() notifications are sent
for any CPU.

Cc: Nicolas Pitre <nicolas.pi...@linaro.org>
Acked-by: Kevin Hilman <khil...@linaro.org>
Signed-off-by: Lina Iyer <lina.i...@linaro.org>
---
 kernel/cpu_pm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index 9656a3c..009cc9a 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
  * low power state that may have caused some blocks in the same power domain
  * to reset.
  *
- * Must be called after cpu_pm_exit has been called on all cpus in the power
+ * Must be called after cpu_cluster_pm_enter has been called for the power
  * domain, and before cpu_pm_exit has been called on any cpu in the power
  * domain. Notified drivers can include VFP co-processor, interrupt controller
  * and its PM extensions, local CPU timers context save/restore which
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC 1/7] arm64: pm/domains: try mutualize CPU domains init between arm/arm64

2015-10-05 Thread Lina Iyer

On Fri, Sep 25 2015 at 07:04 -0600, Marc Titinger wrote:

From: Marc Titinger 

fake path to start testing, eventually move this out of /arch/.
incidently enable PM_GENERIC_DOMAINS for VExpress.


In fact, this could be moved out of ARM. My last series moved it to
drivers/base/power/.

-- Lina


Signed-off-by: Marc Titinger 
---
arch/arm/common/domains.c   | 4 ++--
arch/arm64/Kconfig  | 1 +
arch/arm64/include/asm/arm-pd.h | 1 +
arch/arm64/kernel/Makefile  | 6 ++
arch/arm64/kernel/domains.c | 1 +
5 files changed, 11 insertions(+), 2 deletions(-)
create mode 12 arch/arm64/include/asm/arm-pd.h
create mode 12 arch/arm64/kernel/domains.c

diff --git a/arch/arm/common/domains.c b/arch/arm/common/domains.c
index d3207da..68908d4 100644
--- a/arch/arm/common/domains.c
+++ b/arch/arm/common/domains.c
@@ -20,7 +20,7 @@

#include 

-#define NAME_MAX 36
+#define GENPD_NAME_MAX 36

struct arm_pm_domain {
struct generic_pm_domain genpd;
@@ -182,7 +182,7 @@ static int __init arm_domain_init(void)
}

/* Initialize rest of CPU PM domain specifics */
-   pd->genpd.name = kstrndup(np->name, NAME_MAX, GFP_KERNEL);
+   pd->genpd.name = kstrndup(np->name, GENPD_NAME_MAX, GFP_KERNEL);
pd->genpd.power_off = arm_pd_power_down;
pd->genpd.power_on = arm_pd_power_up;
pd->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7c55a63..d35f213 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -250,6 +250,7 @@ config ARCH_VEXPRESS
select COMMON_CLK_VERSATILE
select POWER_RESET_VEXPRESS
select VEXPRESS_CONFIG
+   select PM_GENERIC_DOMAINS if PM
help
  This enables support for the ARMv8 software model (Versatile
  Express).
diff --git a/arch/arm64/include/asm/arm-pd.h b/arch/arm64/include/asm/arm-pd.h
new file mode 12
index 000..ecc5437
--- /dev/null
+++ b/arch/arm64/include/asm/arm-pd.h
@@ -0,0 +1 @@
+../../../arm/include/asm/arm-pd.h
\ No newline at end of file
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 426d076..4689565 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -30,6 +30,12 @@ arm64-obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)  += hw_breakpoint.o
arm64-obj-$(CONFIG_CPU_PM)  += sleep.o suspend.o
arm64-obj-$(CONFIG_CPU_IDLE)+= cpuidle.o
+
+# CPU domains: try mutualize for arm/arm64 in a first step.
+# Eventually make this more generic.
+#
+arm64-obj-$(CONFIG_PM_GENERIC_DOMAINS) += domains.o
+
arm64-obj-$(CONFIG_JUMP_LABEL)  += jump_label.o
arm64-obj-$(CONFIG_KGDB)+= kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
diff --git a/arch/arm64/kernel/domains.c b/arch/arm64/kernel/domains.c
new file mode 12
index 000..bf17c69
--- /dev/null
+++ b/arch/arm64/kernel/domains.c
@@ -0,0 +1 @@
+../../arm/common/domains.c
\ No newline at end of file
--
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] soc: qcom: Add support for SAW2 regulators

2015-12-18 Thread Lina Iyer

On Fri, Dec 18 2015 at 09:15 -0700, Georgi Djakov wrote:

The SAW2 (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper)
is part of the SPM subsystem. It is a hardware block found on some of the
Qualcomm chipsets, which regulates the power to the CPU cores. Add some
basic support for it, so that we can do dynamic voltage scaling.

Signed-off-by: Georgi Djakov 
---
drivers/soc/qcom/spm.c |  149 +++-
1 file changed, 148 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b04b05a0904e..03fcee4b85d9 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -20,11 +20,14 @@
#include 
#include 
#include 
+#include 
#include 
#include 
#include 
#include 
#include 
+#include 
+#include 

#include 
#include 
@@ -51,6 +54,8 @@ enum spm_reg {
SPM_REG_PMIC_DLY,
SPM_REG_PMIC_DATA_0,
SPM_REG_PMIC_DATA_1,
+   SPM_REG_RST,
+   SPM_REG_STS_1,
SPM_REG_VCTL,
SPM_REG_SEQ_ENTRY,
SPM_REG_SPM_STS,
@@ -68,9 +73,22 @@ struct spm_reg_data {
u8 start_index[PM_SLEEP_MODE_NR];
};

+struct spm_vlevel_data {
+   struct spm_driver_data *drv;
+   unsigned selector;
+};
+
+struct saw2_vreg {
+   struct regulator_desc   rdesc;
+   struct regulator_dev*rdev;
+   struct spm_driver_data  *drv;
+   u32 selector;
+};
+
struct spm_driver_data {
void __iomem *reg_base;
const struct spm_reg_data *reg_data;
+   struct saw2_vreg *vreg;
};

static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = {
@@ -94,10 +112,13 @@ static const struct spm_reg_data spm_reg_8974_8084_cpu  = {

static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_CFG]   = 0x08,
+   [SPM_REG_STS_1] = 0x10,
+   [SPM_REG_VCTL]  = 0x14,
[SPM_REG_SPM_CTL]   = 0x20,
[SPM_REG_PMIC_DLY]  = 0x24,
[SPM_REG_PMIC_DATA_0]   = 0x28,
[SPM_REG_PMIC_DATA_1]   = 0x2C,
+   [SPM_REG_RST]   = 0x30,
[SPM_REG_SEQ_ENTRY] = 0x80,
};

@@ -282,6 +303,127 @@ static struct cpuidle_ops qcom_cpuidle_ops __initdata = {
CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v1, "qcom,kpss-acc-v1", _cpuidle_ops);
CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v2, "qcom,kpss-acc-v2", _cpuidle_ops);

+static int saw2_regulator_get_voltage(struct regulator_dev *rdev)
+{
+   struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+
+   return regulator_list_voltage_linear_range(rdev, drv->vreg->selector);
+}
+
+static void spm_smp_set_vdd(void *data)
+{
+   struct spm_vlevel_data *vdata = (struct spm_vlevel_data *)data;
+   struct spm_driver_data *drv = vdata->drv;
+   struct saw2_vreg *vreg = drv->vreg;
+   u32 sel = vdata->selector;
+   u32 val, new_val;
+   u32 vctl, data0, data1;
+   int timeout_us = 50;
+
+   if (vreg->selector == sel)
+   return;
+
+   vctl = spm_register_read(drv, SPM_REG_VCTL);
+   data0 = spm_register_read(drv, SPM_REG_PMIC_DATA_0);
+   data1 = spm_register_read(drv, SPM_REG_PMIC_DATA_1);
+
+   /* select the band */
+   val = 0x80 | sel;
+
+   vctl &= ~0xff;
+   vctl |= val;
+
+   data0 &= ~0xff;
+   data0 |= val;
+
+   data1 &= ~0x3f;
+   data1 |= val & 0x3f;
+   data1 &= ~0x3f;
+   data1 |= (val & 0x3f) << 16;
+
+   spm_register_write(drv, SPM_REG_RST, 1);
+   spm_register_write(drv, SPM_REG_VCTL, vctl);
+   spm_register_write(drv, SPM_REG_PMIC_DATA_0, data0);
+   spm_register_write(drv, SPM_REG_PMIC_DATA_1, data1);
+
+   do {
+   new_val = spm_register_read(drv, SPM_REG_STS_1) & 0xff;
+   if (new_val == val)
+   break;
+   udelay(1);
+   } while (--timeout_us);
+
+   if (!timeout_us) {
+   pr_err("%s: Voltage not changed: %#x\n", __func__, new_val);
+   return;
+   }
+
+   if (sel > vreg->selector) {
+   /* PMIC internal slew rate is 1250 uV per us */
+   udelay((sel - vreg->selector) * 10);
+   }
+
+   vreg->selector = sel;
+}
+
+static int saw2_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+   struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+   struct spm_vlevel_data data;
+   int cpu = rdev_get_id(rdev);
+
+   data.drv = drv;
+   data.selector = selector;
+
+   return smp_call_function_single(cpu, spm_smp_set_vdd, , true);
+}
+
+static struct regulator_ops saw2_regulator_ops = {
+   .list_voltage = regulator_list_voltage_linear_range,
+   .set_voltage_sel = saw2_regulator_set_voltage_sel,
+   .get_voltage = saw2_regulator_get_voltage,
+};
+
+static struct regulator_desc saw2_regulator = {
+   .owner = THIS_MODULE,
+   .type = REGULATOR_VOLTAGE,
+   .ops  = _regulator_ops,
+   

Re: [PATCH v4] regulator: qcom-saw: Add support for SAW regulators

2016-02-10 Thread Lina Iyer

On Wed, Feb 10 2016 at 03:13 -0700, Mark Brown wrote:

On Tue, Feb 09, 2016 at 03:21:54PM -0700, Lina Iyer wrote:

On Tue, Feb 09 2016 at 06:13 -0700, Georgi Djakov wrote:


Please delete unneeded context from mails when replying.  Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.


Sorry.


>+#defineSPM_REG_STS_1   0x10
>+#defineSPM_REG_VCTL0x14
>+#defineSPM_REG_PMIC_DATA_0 0x28
>+#defineSPM_REG_PMIC_DATA_1 0x2c
>+#defineSPM_REG_RST 0x30



These register offsets are SoC specific. You may want to follow the model
of drivers/soc/qcom/spm.c in getting register offsets.



While I see that you are only supporting APQ8064 with this patch, you
probably would want to think a bit far ahead. To support any other QCOM
SoC, you would need extensive changes.


This has already been applied.  It's not immediately clear to me that
changes simply to move the registers around would be more extensive than
just adding fields to the driver data, is it more than just that?


The offsets are the simple part. On other QCOM SoCs the voltage is
regulated by the SAW attached to the L2 cache controller. They have a
single rail that supplies power to all the cores and the L2, with
ability to change the number of phases to match the load. This driver
supports 8064 which has individual CPU rails, while the rest of the QCOM
SoC's share a common rail design.

While the regulator changes are orthogonal between 8064 and the rest of
the QCOM SoC's, it might have been nicer to look ahead into other SoC's
that may share similar compatible (with a different version ofcourse),
for the design of this driver. That said, the functionality of the
driver seems like what is needed for 8064 and I wouldnt want to stop the
upstreaming process. It might need changes to abstract offsets,
identifying the SAW regulator that will change the voltage on that SoC
etc., in the future to support both class of SoCs.

Thanks,
Lina



Re: [PATCH v4] regulator: qcom-saw: Add support for SAW regulators

2016-02-09 Thread Lina Iyer

On Tue, Feb 09 2016 at 06:13 -0700, Georgi Djakov wrote:

The SAW (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper)
is part of the SPM subsystem. It is a hardware block in the Qualcomm
chipsets that regulates the power to the CPU cores on platform such as
apq8064, msm8974, apq8084 and others.

Signed-off-by: Georgi Djakov 
---

Changes since v3 (https://lkml.org/lkml/2016/2/3/829)
* Add MFD dependency to Kconfig
* Rename SAW2 to SAW as we may support other SAW generations than just 2
* Increase timeout to 100us

Changes since v2 (https://lkml.org/lkml/2016/1/28/481)
* Address the comments from Mark. Thanks!
- Implement regulator_get_voltage_sel() instead of regulator_get_voltage()
- Add cpu_relax() in the loop
- Specify ramp_delay
- Drop the legacy "regulator-name" property

Changes since v1 (https://lkml.org/lkml/2015/12/18/629)
* Move into a separate regulator driver

.../bindings/regulator/qcom,saw-regulator.txt  |   31 +++
drivers/regulator/Kconfig  |   12 +
drivers/regulator/Makefile |1 +
drivers/regulator/qcom_saw-regulator.c |  229 
4 files changed, 273 insertions(+)
create mode 100644 
Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
create mode 100644 drivers/regulator/qcom_saw-regulator.c

diff --git a/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt 
b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
new file mode 100644
index ..977fec08b2ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
@@ -0,0 +1,31 @@
+Qualcomm SAW Regulators
+
+SAW (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper) is a 
hardware
+block in the Qualcomm chipsets that regulates the power to the CPU cores on 
devices
+such as APQ8064, MSM8974, APQ8084 and others.
+
+- compatible:
+   Usage: required
+   Value type: 
+   Definition: must be one of:
+   "qcom,apq8064-saw2-v1.1-regulator"
+
+Example:
+saw0: power-controller@2089000 {
+   compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", 
"simple-mfd";
+   reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
+   #address-cells = <1>;
+   #size-cells = <1>;
+
+   saw0_regulator: regulator@2089000 {
+   compatible = "qcom,apq8064-saw2-v1.1-regulator";
+   regulator-always-on;
+   regulator-min-microvolt = <825000>;
+   regulator-max-microvolt = <125>;
+   };
+   };
+
+
+{
+   cpu-supply = <_regulator>;
+   };
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 74a6354eaefa..6d5f4fce1d75 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -558,6 +558,18 @@ config REGULATOR_QCOM_RPM
  Qualcomm RPM as a module. The module will be named
  "qcom_rpm-regulator".

+config REGULATOR_QCOM_SAW
+   tristate "Qualcomm SAW regulator driver"
+   depends on (ARCH_QCOM || COMPILE_TEST) && MFD_SYSCON
+   help
+ If you say yes to this option, support will be included for the
+ regulators providing power to the CPU cores on devices such as
+ APQ8064.
+
+ Say M here if you want to include support for the CPU core voltage
+ regulators as a module. The module will be named
+ "qcom_saw-regulator".
+
config REGULATOR_QCOM_SMD_RPM
tristate "Qualcomm SMD based RPM regulator driver"
depends on QCOM_SMD_RPM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 348cfd727350..75a0b4a8f1b2 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  
mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6397)  += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_SAW)+= qcom_saw-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
diff --git a/drivers/regulator/qcom_saw-regulator.c 
b/drivers/regulator/qcom_saw-regulator.c
new file mode 100644
index ..c800f16adaf0
--- /dev/null
+++ b/drivers/regulator/qcom_saw-regulator.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 

Re: [PATCH v2 00/17] Make rpmsg a framework

2016-09-12 Thread Lina Iyer

Hi Bjorn,

On Thu, Sep 01 2016 at 16:28 -0600, Bjorn Andersson wrote:

This series splits the virtio rpmsg bus driver into a rpmsg bus and a virtio
backend/wireformat.


As we discussed the Qualcomm SMD implementation a couple of years back people
suggested that I should make it "a rpmsg thingie". With the introduction of the
Qualcomm 8996 platform, we must support a variant of the communication
mechanism that share many of the characteristics of SMD, but are different
enough that it can't be done in a single implementation. As such there is
enough benefit to do the necessary work and being able to make SMD a "rpmsg
thingie".

On-top of this series I have patches to switch the current smd clients over to
rpmsg (and by that drop the existing SMD implementation).

All this allows me to implement the new backend and reuse all existing SMD
drivers with the new mechanism.



RPM Communication has to supported even when IRQs are disabled. The most
important use of this communication is to set the wake up time for the
CPU subsystem when all the CPUs are powered off. In addition to that,
"sleep" votes that are sent by the application processor subsystem to
allow system to go into deep sleep modes can only be triggered when the
CPU PM domains are power collapsed, drivers do not have a knowledge of
when that happens. This has to be done by a platform code that registers
for CPU PM domain power_off/on callbacks.

Using rpmsg may be nice for RPM SMD communication, but mutexes need to
go away for this driver to be any useful than bare bones active mode
resource requests for QCOM SoCs. By not doing that now, we lock
ourselves out of using this SMD driver in the near future when CPU PM
domains are available in the kernel with an ability to do system low
power modes.

I hope you would make rpmsg work in IRQ disabled contexts first before
porting the SMD driver.

Thanks,
Lina



Changes from v1:
- Split up the patch moving core code to rpmsg_core into several commits
- Dropped the wrapping struct in rpmsg_core and just added the ops to the
 public API (but hid the implementation details)
- Reordered things to reduce the size of the later patches

Bjorn Andersson (17):
 rpmsg: Enable matching devices with drivers based on DT
 rpmsg: Name rpmsg devices based on channel id
 rpmsg: rpmsg_send() operations takes rpmsg_endpoint
 rpmsg: Make rpmsg_create_ept() take channel_info struct
 rpmsg: Clean up rpmsg device vs channel naming
 rpmsg: Introduce indirection table for rpmsg_device operations
 rpmsg: Move rpmsg_device API to new file
 rpmsg: Indirection table for rpmsg_endpoint operations
 rpmsg: Move endpoint related interface to rpmsg core
 rpmsg: Move helper for finding rpmsg devices to core
 rpmsg: Split off generic tail of create_channel()
 rpmsg: Split rpmsg core and virtio backend
 rpmsg: Hide rpmsg indirection tables
 rpmsg: virtio: Hide vrp pointer from the public API
 rpmsg: Move virtio specifics from public header
 rpmsg: Allow callback to return errors
 rpmsg: Introduce Qualcomm SMD backend

drivers/remoteproc/Kconfig  |4 +-
drivers/rpmsg/Kconfig   |   14 +
drivers/rpmsg/Makefile  |4 +-
drivers/rpmsg/qcom_smd.c| 1434 +++
drivers/rpmsg/rpmsg_core.c  |  498 
drivers/rpmsg/rpmsg_internal.h  |   82 ++
drivers/rpmsg/virtio_rpmsg_bus.c|  487 +---
include/linux/rpmsg.h   |  246 +-
samples/rpmsg/rpmsg_client_sample.c |   14 +-
9 files changed, 2266 insertions(+), 517 deletions(-)
create mode 100644 drivers/rpmsg/qcom_smd.c
create mode 100644 drivers/rpmsg/rpmsg_core.c
create mode 100644 drivers/rpmsg/rpmsg_internal.h

--
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 00/17] Make rpmsg a framework

2016-09-12 Thread Lina Iyer

On Mon, Sep 12 2016 at 10:52 -0600, Lina Iyer wrote:

Hi Bjorn,

On Thu, Sep 01 2016 at 16:28 -0600, Bjorn Andersson wrote:

This series splits the virtio rpmsg bus driver into a rpmsg bus and a virtio
backend/wireformat.


As we discussed the Qualcomm SMD implementation a couple of years back people
suggested that I should make it "a rpmsg thingie". With the introduction of the
Qualcomm 8996 platform, we must support a variant of the communication
mechanism that share many of the characteristics of SMD, but are different
enough that it can't be done in a single implementation. As such there is
enough benefit to do the necessary work and being able to make SMD a "rpmsg
thingie".

On-top of this series I have patches to switch the current smd clients over to
rpmsg (and by that drop the existing SMD implementation).

All this allows me to implement the new backend and reuse all existing SMD
drivers with the new mechanism.



RPM Communication has to supported even when IRQs are disabled. The most
important use of this communication is to set the wake up time for the
CPU subsystem when all the CPUs are powered off. In addition to that,
"sleep" votes that are sent by the application processor subsystem to
allow system to go into deep sleep modes can only be triggered when the
CPU PM domains are power collapsed, drivers do not have a knowledge of
when that happens. This has to be done by a platform code that registers
for CPU PM domain power_off/on callbacks.


Ok, my bad. These two cases are not critical for the SoC supported by
this driver. So you are good to go from cpuidle perspective


Using rpmsg may be nice for RPM SMD communication, but mutexes need to
go away for this driver to be any useful than bare bones active mode
resource requests for QCOM SoCs. By not doing that now, we lock
ourselves out of using this SMD driver in the near future when CPU PM
domains are available in the kernel with an ability to do system low
power modes.

I hope you would make rpmsg work in IRQ disabled contexts first before
porting the SMD driver.

Thanks,
Lina



Changes from v1:
- Split up the patch moving core code to rpmsg_core into several commits
- Dropped the wrapping struct in rpmsg_core and just added the ops to the
public API (but hid the implementation details)
- Reordered things to reduce the size of the later patches

Bjorn Andersson (17):
rpmsg: Enable matching devices with drivers based on DT
rpmsg: Name rpmsg devices based on channel id
rpmsg: rpmsg_send() operations takes rpmsg_endpoint
rpmsg: Make rpmsg_create_ept() take channel_info struct
rpmsg: Clean up rpmsg device vs channel naming
rpmsg: Introduce indirection table for rpmsg_device operations
rpmsg: Move rpmsg_device API to new file
rpmsg: Indirection table for rpmsg_endpoint operations
rpmsg: Move endpoint related interface to rpmsg core
rpmsg: Move helper for finding rpmsg devices to core
rpmsg: Split off generic tail of create_channel()
rpmsg: Split rpmsg core and virtio backend
rpmsg: Hide rpmsg indirection tables
rpmsg: virtio: Hide vrp pointer from the public API
rpmsg: Move virtio specifics from public header
rpmsg: Allow callback to return errors
rpmsg: Introduce Qualcomm SMD backend

drivers/remoteproc/Kconfig  |4 +-
drivers/rpmsg/Kconfig   |   14 +
drivers/rpmsg/Makefile  |4 +-
drivers/rpmsg/qcom_smd.c| 1434 +++
drivers/rpmsg/rpmsg_core.c  |  498 
drivers/rpmsg/rpmsg_internal.h  |   82 ++
drivers/rpmsg/virtio_rpmsg_bus.c|  487 +---
include/linux/rpmsg.h   |  246 +-
samples/rpmsg/rpmsg_client_sample.c |   14 +-
9 files changed, 2266 insertions(+), 517 deletions(-)
create mode 100644 drivers/rpmsg/qcom_smd.c
create mode 100644 drivers/rpmsg/rpmsg_core.c
create mode 100644 drivers/rpmsg/rpmsg_internal.h

--
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: linux-next: manual merge of the pm tree with the imx-mxs tree

2016-10-24 Thread Lina Iyer

On Tue, Oct 25 2016 at 17:51 -0600, Rafael J. Wysocki wrote:

On Tuesday, October 25, 2016 10:47:29 AM Stephen Rothwell wrote:

Hi Rafael,

Today's linux-next merge of the pm tree got a conflict in:

  arch/arm/mach-imx/gpc.c

between commits:

  eef0b282bb58 ("ARM: imx: gpc: Initialize all power domains")
  f9d1f7a7ad91 ("ARM: imx: gpc: Fix the imx_gpc_genpd_init() error path")

from the imx-mxs tree and commit:

  59d65b73a23c ("PM / Domains: Make genpd state allocation dynamic")

from the pm tree.

I fixed it up (see below) and can carry the fix as necessary.


Thanks Stephen!

Lina, please have a look at the Stephen's fix and let me know if that
conflict should be resolved in a different way.


Hi Rafael,
Stephen's conflict resolution seems correct. Thanks Stephen.

-- Lina


Re: [PATCH v7 04/10] drivers: qcom: rpmh: add RPMH helper functions

2018-05-14 Thread Lina Iyer

On Fri, May 11 2018 at 14:14 -0600, Doug Anderson wrote:

Hi,

On Fri, May 11, 2018 at 8:06 AM, Lina Iyer <il...@codeaurora.org> wrote:

As I've said I haven't reviewed RPMh in any amount of detail and so
perhaps I don't understand something.

OK, I dug a little more and coded up something for you.  Basically
you're doing a whole bunch of iteration / extra work here to try to
come up with a way to associate an extra bit of data with each "struct
rsc_drv".  Rather than that, just add an extra field into "struct
rsc_drv".  Problem solved.

See http://crosreview.com/1054646 for what I mean.


I tried to avoid such pointer references and keep it object oriented
with this approach. I agree that we run through a list of 2 (at the max)
RSC to get the drv* from the rpmh_ctrlr. It is not going to be
expensive.


Even if you wanted to keep things "object oriented" then IMHO your
code still should change.  Sure, it's not computationally expensive to
iterate through this list, but it adds an extra level of complexity
that doesn't seem justified.

If you _really_ needed an abstraction barrier then at least add a
"void *client_data" to "struct rsc_drv.c".  At least you'd get rid of
the ugly global list and store your pointer directly in the correct
structure rather than creating an external entity.  Now it becomes
100% obvious that there is exactly 1 "struct rpmh_ctrlr" for each
controller.  ...but IMO there's enough intertwining between "rpmh.c"
and "rpmh-rsc.c" that it would just be a waste because now you'd need
to do extra memory allocation and freeing.  ...and if you just
allocated the pointer in get_rpmh_ctrlr() it would also seem non-ideal
because this one-time allocation (that affects _all_ RPMh clients)
happens whenever one client happens to do the first access.  This is
one-time init so it makes sense to do it at init time.

I say that there's intertwining between "rpmh.c" and "rpmh-rsc.c"
because both C files call directly into one another and have intimate
knowledge of how the other works.  They aren't really separate things.
Specifically I see that "rpmh-rsc" directly calls into "rpmh.c" when
it calls rpmh_tx_done(), and of coruse "rpmh-rsc.c" directly calls
into "rpmh.c".


OK, so I've been browsing through the source code more so I can be a
little more informed here.  As far as I can tell "rpmh.c"'s goal is:

1. Put a simpler API atop "rpmh-rsc.c".  ...but why not just put that
API directly into "rpmh-rsc.c" anyway?  If there was someone that
needed the more complex API then having a "simpler" wrapper makes
sense, but that's not the case, is it?

2. Add caching atop "rpmh-rsc"


I'll respond to some of your other patches too, but I think that the
amount of code for caching is not very much.  I don't see the benefit
of trying to split the code into two files.  Put them into one and
then delete all the extra code you needed just the try to maintain
some abstraction.



Another things this helps with is that, if the driver is not a child of
the RSC nodes in DT, then the drvdata of the parent would not a RSC node
and accessing that would result in a crash. This offers a cleaner exit
path for the error case.


Why would the driver not be a child of the RSC nodes?  That's kinda
like saying "if you try to instantiate an i2c device as a platform
device then its probe will crash".  Yeah, it will.  Doctor, it hurts
if I poke myself in my eye with this sharp stick, do you have any
medicine that can help fix that?



I'll try to dig into this more so I could just be confused, but in
general it seems really odd to have a spinlock and something called a
"cache" at this level.  If we need some sort of mutual exclusion or
caching it seems like it should be stored in memory directly
associated with the RPMh device, not some external global.


The idea behind the locking is not to avoid the race between rpmh.c and
rpmh-rsc.c. From the DT, the devices that are dependent on the RSCs are
probed following the probe of the controller. And init is not that we are
worried about.
The condition here is to prevent the rpmh_rsc[] from being modified
concurrently by drivers.



OK, I see the point of the locking now, but not the list still.
Sounds like Matthias agrees with me that the list isn't useful.  Seems
like you should squash my patch at http://crosreview.com/1042883 into
yours.


I saw your approach. I am okay with it for your tree,


I'm not okay with it for the Chrome OS tree.  We need to match
upstream, not fork for style reasons.  I'd rather take a driver that I
think it overly complex but matches upstream than a private driver.



my approach comes
out of experiences in qcom platforms and how things tend to shape up in
the future. I would want you to consider my reasoning as well, before we
go forward.


I

Re: [PATCH v8 09/10] drivers: qcom: rpmh: add support for batch RPMH request

2018-05-14 Thread Lina Iyer


Hi Doug,

Will explain only the key points now.

On Fri, May 11 2018 at 14:19 -0600, Doug Anderson wrote:

Hi,

On Wed, May 9, 2018 at 10:01 AM, Lina Iyer <il...@codeaurora.org> wrote:

 /**
@@ -77,12 +82,14 @@ struct rpmh_request {
  * @cache: the list of cached requests
  * @lock: synchronize access to the controller data
  * @dirty: was the cache updated since flush
+ * @batch_cache: Cache sleep and wake requests sent as batch
  */
 struct rpmh_ctrlr {
struct rsc_drv *drv;
struct list_head cache;
spinlock_t lock;
bool dirty;
+   const struct rpmh_request *batch_cache[RPMH_MAX_BATCH_CACHE];


I'm pretty confused about why the "batch_cache" is separate from the
normal cache.  As far as I can tell the purpose of the two is the same
but you have two totally separate code paths and data structures.


Due to a hardware limitation, requests made by bus drivers must be set
up in the sleep and wake TCS first before setting up the requests from
other drivers. Bus drivers use batch mode for any and all RPMH
communication. Hence their request are the only ones in the batch_cache.



 };

 static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_CTRLR];
@@ -133,6 +140,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
msg);
struct completion *compl = rpm_msg->completion;
+   atomic_t *wc = rpm_msg->wait_count;

rpm_msg->err = r;

@@ -143,8 +151,13 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
kfree(rpm_msg->free);

/* Signal the blocking thread we are done */
-   if (compl)
-   complete(compl);
+   if (!compl)
+   return;


The comment above this "if" block no longer applies to the line next
to it after your patch.  ...but below I suggest you get rid of
"wait_count", so maybe this part of the patch will go away.



+static int cache_batch(struct rpmh_ctrlr *ctrlr,
+  struct rpmh_request **rpm_msg, int count)
+{
+   unsigned long flags;
+   int ret = 0;
+   int index = 0;
+   int i;
+
+   spin_lock_irqsave(>lock, flags);
+   while (index < RPMH_MAX_BATCH_CACHE && ctrlr->batch_cache[index])
+   index++;
+   if (index + count >= RPMH_MAX_BATCH_CACHE) {
+   ret = -ENOMEM;
+   goto fail;
+   }
+
+   for (i = 0; i < count; i++)
+   ctrlr->batch_cache[index + i] = rpm_msg[i];
+fail:


Nit: this label is for both failure and normal exit, so call it "exit".



+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}


As part of my overall confusion about why the batch cache is different
than the normal one: for the normal use case you still call
rpmh_rsc_write_ctrl_data() for things you put in your cache, but you
don't for the batch cache.  I still haven't totally figured out what
rpmh_rsc_write_ctrl_data() does, but it seems strange that you don't
do it for the batch cache but you do for the other one.



flush_batch does write to the controller using
rpmh_rsc_write_ctrl_data()

Thanks,
Lina


+/**
+ * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
+ * batch to finish.
+ *
+ * @dev: the device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The array of count of elements in each batch, 0 terminated.
+ *
+ * Write a request to the RSC controller without caching. If the request
+ * state is ACTIVE, then the requests are treated as completion request
+ * and sent to the controller immediately. The function waits until all the
+ * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the
+ * request is sent as fire-n-forget and no ack is expected.
+ *
+ * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests.
+ */
+int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
+const struct tcs_cmd *cmd, u32 *n)
+{
+   struct rpmh_request *rpm_msg[RPMH_MAX_REQ_IN_BATCH] = { NULL };
+   DECLARE_COMPLETION_ONSTACK(compl);
+   atomic_t wait_count = ATOMIC_INIT(0);
+   struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+   int count = 0;
+   int ret, i;
+
+   if (IS_ERR(ctrlr) || !cmd || !n)
+   return -EINVAL;
+
+   while (n[count++] > 0)
+   ;
+   count--;
+   if (!count || count > RPMH_MAX_REQ_IN_BATCH)
+   return -EINVAL;
+
+   for (i = 0; i < count; i++) {
+   rpm_msg[i] = __get_rpmh_msg_async(state, cmd, n[i]);
+   if (IS_ERR_OR_NULL(rpm_msg[i])) {


Just "IS_ERR".  It's never NULL.

...also add a i-- somewhere in here or you're going to be kfree()ing
your error value, aren't you?



+   ret = PTR_ERR(rpm_m

Re: [PATCH] drivers: thermal: step_wise: add support for hysteresis

2018-05-09 Thread Lina Iyer

Hi Daniel,

On Tue, May 08 2018 at 20:04 -0600, Daniel Lezcano wrote:

On Mon, May 07, 2018 at 11:54:08AM -0600, Lina Iyer wrote:

From: Ram Chandrasekar <rkumb...@codeaurora.org>

From: Ram Chandrasekar <rkumb...@codeaurora.org>

Step wise governor increases the mitigation level when the temperature
goes above a threshold and will decrease the mitigation when the
temperature falls below the threshold. If it were a case, where the
temperature hovers around a threshold, the mitigation will be applied
and removed at every iteration. This reaction to the temperature is
inefficient for performance.

The use of hysteresis temperature could avoid this ping-pong of
mitigation by relaxing the mitigation to happen only when the
temperature goes below this lower hysteresis value.


I don't disagree with this but the ping-pong around a temperature is usually
avoided with a P-I-D computation which is implemented with the IPA governor.
Wouldn't be more interesting to add the power numbers like some other
platforms, so the IPA could be used?


Possibly. But we have had better thermal performance for our hardware, with
stepwise and custom governor. Much of the mitigation happens through the
firmware and hardware. The stepwise governor works well for us.


You will probably have better results with the IPA than changing the step-wise
governor behavior (which may potentially impact other users).


This should not impact others who have not implemented the
->get_trip_hyst method.

Thanks,
Lina



[PATCH v8 05/10] drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS

2018-05-09 Thread Lina Iyer
Sleep and wake requests are sent when the application processor
subsystem of the SoC is entering deep sleep states like in suspend.
These requests help lower the system power requirements when the
resources are not in use.

Sleep and wake requests are written to the TCS slots but are not
triggered at the time of writing. The TCS are triggered by the firmware
after the last of the CPUs has executed its WFI. Since these requests
may come in different batches of requests, it is the job of this
controller driver to find and arrange the requests into the available
TCSes.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Evan Green <evgr...@chromium.org>

---
Changes in v8:
- Bounds check in find_match()

Changes in v7:
- Bug fix in find_match()
---
 drivers/soc/qcom/rpmh-internal.h |   8 ++
 drivers/soc/qcom/rpmh-rsc.c  | 122 +++
 2 files changed, 130 insertions(+)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index d9a21726e568..6e19fe458c31 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -14,6 +14,7 @@
 #define MAX_CMDS_PER_TCS   16
 #define MAX_TCS_PER_TYPE   3
 #define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define MAX_TCS_SLOTS  (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
 #define RPMH_MAX_CTRLR 2
 
 struct rsc_drv;
@@ -30,6 +31,8 @@ struct rsc_drv;
  * @ncpt:  number of commands in each TCS
  * @lock:  lock for synchronizing this TCS writes
  * @req:   requests that are sent from the TCS
+ * @cmd_cache: flattened cache of cmds in sleep/wake TCS
+ * @slots: indicates which of @cmd_addr are occupied
  */
 struct tcs_group {
struct rsc_drv *drv;
@@ -40,6 +43,8 @@ struct tcs_group {
int ncpt;
spinlock_t lock;
const struct tcs_request *req[MAX_TCS_PER_TYPE];
+   u32 *cmd_cache;
+   DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
 };
 
 /**
@@ -69,6 +74,9 @@ struct rsc_drv {
 extern struct list_head rsc_drv_list;
 
 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
+int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
+const struct tcs_request *msg);
+int rpmh_rsc_invalidate(struct rsc_drv *drv);
 
 void rpmh_tx_done(const struct tcs_request *msg, int r);
 
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index c0edf3850147..b5894b001ae1 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -113,6 +113,12 @@ static struct tcs_group *get_tcs_for_msg(struct rsc_drv 
*drv,
case RPMH_ACTIVE_ONLY_STATE:
type = ACTIVE_TCS;
break;
+   case RPMH_WAKE_ONLY_STATE:
+   type = WAKE_TCS;
+   break;
+   case RPMH_SLEEP_STATE:
+   type = SLEEP_TCS;
+   break;
default:
return ERR_PTR(-EINVAL);
}
@@ -353,6 +359,109 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct 
tcs_request *msg)
 }
 EXPORT_SYMBOL(rpmh_rsc_send_data);
 
+static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd,
+ int len)
+{
+   int i, j;
+
+   /* Check for already cached commands */
+   for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
+   if (tcs->cmd_cache[i] != cmd[0].addr)
+   continue;
+   if (i + len >= MAX_TCS_SLOTS)
+   goto seq_err;
+   for (j = 0; j < len; j++) {
+   if (tcs->cmd_cache[i + j] != cmd[j].addr)
+   goto seq_err;
+   }
+   return i;
+   }
+
+   return -ENODATA;
+
+seq_err:
+   WARN(1, "Message does not match previous sequence.\n");
+   return -EINVAL;
+}
+
+static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
+ int *tcs_id, int *cmd_id)
+{
+   int slot, offset;
+   int i = 0;
+
+   /* Find if we already have the msg in our TCS */
+   slot = find_match(tcs, msg->cmds, msg->num_cmds);
+   if (slot >= 0)
+   goto copy_data;
+
+   /* Do over, until we can fit the full payload in a TCS */
+   do {
+   slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
+ i, msg->num_cmds, 0);
+   if (slot == MAX_TCS_SLOTS)
+   return -ENOMEM;
+   i += tcs->ncpt;
+   } while (slot + msg->num_cmds - 1 >= i);
+
+copy_data:
+   bitmap_set(tcs->slots, slot, msg->num_cmds);
+   /* Copy the addresses of the resources over to the slots */
+   for (i = 0; i < msg->num_cmds; i++)
+   tcs->cmd_cache[slot + i] = msg->cmds[i].addr;
+
+   offset = slot / tcs-&g

[PATCH v8 09/10] drivers: qcom: rpmh: add support for batch RPMH request

2018-05-09 Thread Lina Iyer
Platform drivers need make a lot of resource state requests at the same
time, say, at the start or end of an usecase. It can be quite
inefficient to send each request separately. Instead they can give the
RPMH library a batch of requests to be sent and wait on the whole
transaction to be complete.

rpmh_write_batch() is a blocking call that can be used to send multiple
RPMH command sets. Each RPMH command set is set asynchronously and the
API blocks until all the command sets are complete and receive their
tx_done callbacks.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- Check for loop out of bounds

Changes in v6:
- replace rpmh_client with device *
Changes in v4:
- reorganize rpmh_write_batch()
- introduce wait_count here, instead of patch#4
---
 drivers/soc/qcom/rpmh.c | 154 +++-
 include/soc/qcom/rpmh.h |   8 +++
 2 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 1bb62876795c..a0e277b4b846 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -21,6 +21,8 @@
 #include "rpmh-internal.h"
 
 #define RPMH_TIMEOUT_MSmsecs_to_jiffies(1)
+#define RPMH_MAX_REQ_IN_BATCH  10
+#define RPMH_MAX_BATCH_CACHE   (2 * RPMH_MAX_REQ_IN_BATCH)
 
 #define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name)   \
struct rpmh_request name = {\
@@ -34,6 +36,7 @@
.completion = q,\
.dev = dev, \
.free = NULL,   \
+   .wait_count = NULL, \
}
 
 /**
@@ -60,6 +63,7 @@ struct cache_req {
  * @dev: the device making the request
  * @err: err return from the controller
  * @free: the request object to be freed at tx_done
+ * @wait_count: count of waiters for this completion
  */
 struct rpmh_request {
struct tcs_request msg;
@@ -68,6 +72,7 @@ struct rpmh_request {
const struct device *dev;
int err;
struct rpmh_request *free;
+   atomic_t *wait_count;
 };
 
 /**
@@ -77,12 +82,14 @@ struct rpmh_request {
  * @cache: the list of cached requests
  * @lock: synchronize access to the controller data
  * @dirty: was the cache updated since flush
+ * @batch_cache: Cache sleep and wake requests sent as batch
  */
 struct rpmh_ctrlr {
struct rsc_drv *drv;
struct list_head cache;
spinlock_t lock;
bool dirty;
+   const struct rpmh_request *batch_cache[RPMH_MAX_BATCH_CACHE];
 };
 
 static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_CTRLR];
@@ -133,6 +140,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
msg);
struct completion *compl = rpm_msg->completion;
+   atomic_t *wc = rpm_msg->wait_count;
 
rpm_msg->err = r;
 
@@ -143,8 +151,13 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
kfree(rpm_msg->free);
 
/* Signal the blocking thread we are done */
-   if (compl)
-   complete(compl);
+   if (!compl)
+   return;
+
+   if (wc && !atomic_dec_and_test(wc))
+   return;
+
+   complete(compl);
 }
 EXPORT_SYMBOL(rpmh_tx_done);
 
@@ -332,6 +345,137 @@ int rpmh_write(const struct device *dev, enum rpmh_state 
state,
 }
 EXPORT_SYMBOL(rpmh_write);
 
+static int cache_batch(struct rpmh_ctrlr *ctrlr,
+  struct rpmh_request **rpm_msg, int count)
+{
+   unsigned long flags;
+   int ret = 0;
+   int index = 0;
+   int i;
+
+   spin_lock_irqsave(>lock, flags);
+   while (index < RPMH_MAX_BATCH_CACHE && ctrlr->batch_cache[index])
+   index++;
+   if (index + count >= RPMH_MAX_BATCH_CACHE) {
+   ret = -ENOMEM;
+   goto fail;
+   }
+
+   for (i = 0; i < count; i++)
+   ctrlr->batch_cache[index + i] = rpm_msg[i];
+fail:
+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}
+
+static int flush_batch(struct rpmh_ctrlr *ctrlr)
+{
+   const struct rpmh_request *rpm_msg;
+   unsigned long flags;
+   int ret = 0;
+   int i;
+
+   /* Send Sleep/Wake requests to the controller, expect no response */
+   spin_lock_irqsave(>lock, flags);
+   for (i = 0; ctrlr->batch_cache[i]; i++) {
+   rpm_msg = ctrlr->batch_cache[i];
+   ret = rpmh_rsc_write_ctrl_data(ctrlr->drv, _msg->msg);
+   if (ret)
+   break;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}
+
+static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
+{
+   unsigned long flags;
+   int index = 0;

[PATCH v8 07/10] drivers: qcom: rpmh: cache sleep/wake state requests

2018-05-09 Thread Lina Iyer
Active state requests are sent immediately to the RSC controller, while
sleep and wake state requests are cached in this driver to avoid taxing
the RSC controller repeatedly. The cached values will be sent to the
controller when the rpmh_flush() is called.

Generally, flushing is a system PM activity and may be called from the
system PM drivers when the system is entering suspend or deeper sleep
modes during cpuidle.

Also allow invalidating the cached requests, so they may be re-populated
again.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Evan Green <evgr...@chromium.org>
Reviewed-by: Matthias Kaehlcke <m...@chromium.org>
---

Changes in v6:
- replace rpmh_client with device *

Changes in v4:
- remove locking for ->dirty in invalidate
- fix send_single
Changes in v3:
- Remove locking for flush function
- Improve comments
---
 drivers/soc/qcom/rpmh.c | 217 +++-
 include/soc/qcom/rpmh.h |  11 ++
 2 files changed, 223 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 74bb82339b01..23fcbd9487cd 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -7,10 +7,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -33,6 +35,21 @@
.dev = dev, \
}
 
+/**
+ * struct cache_req: the request object for caching
+ *
+ * @addr: the address of the resource
+ * @sleep_val: the sleep vote
+ * @wake_val: the wake vote
+ * @list: linked list obj
+ */
+struct cache_req {
+   u32 addr;
+   u32 sleep_val;
+   u32 wake_val;
+   struct list_head list;
+};
+
 /**
  * struct rpmh_request: the message to be sent to rpmh-rsc
  *
@@ -54,9 +71,15 @@ struct rpmh_request {
  * struct rpmh_ctrlr: our representation of the controller
  *
  * @drv: the controller instance
+ * @cache: the list of cached requests
+ * @lock: synchronize access to the controller data
+ * @dirty: was the cache updated since flush
  */
 struct rpmh_ctrlr {
struct rsc_drv *drv;
+   struct list_head cache;
+   spinlock_t lock;
+   bool dirty;
 };
 
 static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_CTRLR];
@@ -91,6 +114,8 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device 
*dev)
break;
}
rpmh_rsc[i].drv = drv;
+   spin_lock_init(_rsc[i].lock);
+   INIT_LIST_HEAD(_rsc[i].cache);
ctrlr = _rsc[i];
break;
}
@@ -118,29 +143,109 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
 }
 EXPORT_SYMBOL(rpmh_tx_done);
 
+static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr)
+{
+   struct cache_req *p, *req = NULL;
+
+   list_for_each_entry(p, >cache, list) {
+   if (p->addr == addr) {
+   req = p;
+   break;
+   }
+   }
+
+   return req;
+}
+
+static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
+  enum rpmh_state state,
+  struct tcs_cmd *cmd)
+{
+   struct cache_req *req;
+   unsigned long flags;
+
+   spin_lock_irqsave(>lock, flags);
+   req = __find_req(ctrlr, cmd->addr);
+   if (req)
+   goto existing;
+
+   req = kzalloc(sizeof(*req), GFP_ATOMIC);
+   if (!req) {
+   req = ERR_PTR(-ENOMEM);
+   goto unlock;
+   }
+
+   req->addr = cmd->addr;
+   req->sleep_val = req->wake_val = UINT_MAX;
+   INIT_LIST_HEAD(>list);
+   list_add_tail(>list, >cache);
+
+existing:
+   switch (state) {
+   case RPMH_ACTIVE_ONLY_STATE:
+   if (req->sleep_val != UINT_MAX)
+   req->wake_val = cmd->data;
+   break;
+   case RPMH_WAKE_ONLY_STATE:
+   req->wake_val = cmd->data;
+   break;
+   case RPMH_SLEEP_STATE:
+   req->sleep_val = cmd->data;
+   break;
+   default:
+   break;
+   };
+
+   ctrlr->dirty = true;
+unlock:
+   spin_unlock_irqrestore(>lock, flags);
+
+   return req;
+}
+
 /**
- * __rpmh_write: send the RPMH request
+ * __rpmh_write: Cache and send the RPMH request
  *
  * @dev: The device making the request
  * @state: Active/Sleep request type
  * @rpm_msg: The data that needs to be sent (cmds).
+ *
+ * Cache the RPMH request and send if the state is ACTIVE_ONLY.
+ * SLEEP/WAKE_ONLY requests are not sent to the controller at
+ * this time. Use rpmh_flush() to send them to the controller.
  */
 static int __rpmh_write(const struct device *dev, enum rpmh_state state,

[PATCH v8 10/10] drivers: qcom: rpmh-rsc: allow active requests from wake TCS

2018-05-09 Thread Lina Iyer
Some RSCs may only have sleep and wake TCS, i.e, there is no dedicated
TCS for active mode request, but drivers may still want to make active
requests from these RSCs. In such cases re-purpose the wake TCS to send
active state requests.

The requirement for this is that the driver is aware that the wake TCS
is being repurposed to send active request, hence the sleep and wake
TCSes be invalidated before the active request is sent.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <m...@chromium.org>
---
 drivers/soc/qcom/rpmh-rsc.c | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 68c25ebbbe09..369b9b3eedc5 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -153,6 +153,7 @@ static struct tcs_group *get_tcs_for_msg(struct rsc_drv 
*drv,
 const struct tcs_request *msg)
 {
int type;
+   struct tcs_group *tcs;
 
switch (msg->state) {
case RPMH_ACTIVE_ONLY_STATE:
@@ -168,7 +169,22 @@ static struct tcs_group *get_tcs_for_msg(struct rsc_drv 
*drv,
return ERR_PTR(-EINVAL);
}
 
-   return get_tcs_of_type(drv, type);
+   /*
+* If we are making an active request on a RSC that does not have a
+* dedicated TCS for active state use, then re-purpose a wake TCS to
+* send active votes.
+* NOTE: The driver must be aware that this RSC does not have a
+* dedicated AMC, and therefore would invalidate the sleep and wake
+* TCSes before making an active state request.
+*/
+   tcs = get_tcs_of_type(drv, type);
+   if (msg->state == RPMH_ACTIVE_ONLY_STATE && IS_ERR(tcs)) {
+   tcs = get_tcs_of_type(drv, WAKE_TCS);
+   if (!IS_ERR(tcs))
+   rpmh_rsc_invalidate(drv);
+   }
+
+   return tcs;
 }
 
 static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v8 0/2] drivers/qcom: add Command DB support

2018-05-09 Thread Lina Iyer

Hi Andy, David,

These patches have been reviewed by our peers and have recieved no
further comments in the past few weeks. Would you consider merging this
in your trees?

Thanks,
Lina


On Tue, Apr 10 2018 at 11:57 -0600, Lina Iyer wrote:

Changes since v7:
- Add reviewed-by tags
- Fix example

Changes since v6:
   - Fix 'reg' property
   - Add reviewed-by tags

Changes since v5:
   - Remove indirection of command db start address
   - Rebase on top of 4.16

Changes since v4:
   - Address comments from Stephen and Bjorn

These patches add support for reading a shared memory database in the newer
QCOM SoCs called Command DB. With the new architecture on SDM845, shared
resources like clocks, regulators etc., have dynamic properties. These
properties may change based on external components, board configurations or
available feature set. A remote processor detects these parameters and fills up
the database with the resource and available state information. Platform
drivers that need these shared resources will need to query this database to
get the address and properties and vote for the state.

The information in the database is static. The database is read-only memory
location that is available for Linux. A pre-defined string is used as a key into
an entry in the database. Generally, platform drivers query the database only
at init to get the information they need.

[v1]: https://www.spinics.net/lists/linux-arm-msm/msg32462.html
[v2]: https://lkml.org/lkml/2018/2/8/588
[v3]: https://lkml.org/lkml/2018/2/16/842
[v4]: https://patchwork.kernel.org/patch/10242935/
[v5]: https://lkml.org/lkml/2018/3/14/787
[v6]: https://lkml.org/lkml/2018/4/5/451
[v7]: https://lkml.org/lkml/2018/4/6/756

Lina Iyer (2):
 drivers: qcom: add command DB driver
 dt-bindings: introduce Command DB for QCOM SoCs

.../bindings/reserved-memory/qcom,cmd-db.txt   |  37 +++
drivers/of/platform.c  |   1 +
drivers/soc/qcom/Kconfig   |   9 +
drivers/soc/qcom/Makefile  |   1 +
drivers/soc/qcom/cmd-db.c  | 310 +
include/soc/qcom/cmd-db.h  |  45 +++
6 files changed, 403 insertions(+)
create mode 100644 
Documentation/devicetree/bindings/reserved-memory/qcom,cmd-db.txt
create mode 100644 drivers/soc/qcom/cmd-db.c
create mode 100644 include/soc/qcom/cmd-db.h

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v8 03/10] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE

2018-05-09 Thread Lina Iyer
Log sent RPMH requests and interrupt responses in FTRACE.

Cc: Steven Rostedt <rost...@goodmis.org>
Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- varible name changes and white space

Changes in v6:
- struct tcs_response was removed. Fix in trace as well.
Changes in v4:
- fix compilation issues, use __assign_str
- use %#x instead of 0x%08x
Changes in v3:
- Use __string() instead of char *
- fix TRACE_INCLUDE_PATH
---
 drivers/soc/qcom/Makefile |  1 +
 drivers/soc/qcom/rpmh-rsc.c   | 11 -
 drivers/soc/qcom/trace-rpmh.h | 82 +++
 3 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/qcom/trace-rpmh.h

diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 39d3a059ee50..cb6300f6a8e9 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+CFLAGS_rpmh-rsc.o := -I$(src)
 obj-$(CONFIG_QCOM_GLINK_SSR) +=glink_ssr.o
 obj-$(CONFIG_QCOM_GSBI)+=  qcom_gsbi.o
 obj-$(CONFIG_QCOM_MDT_LOADER)  += mdt_loader.o
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 4eeccf75cc15..0a8cec9d1651 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -24,6 +24,9 @@
 
 #include "rpmh-internal.h"
 
+#define CREATE_TRACE_POINTS
+#include "trace-rpmh.h"
+
 #define RSC_DRV_TCS_OFFSET 672
 #define RSC_DRV_CMD_OFFSET 20
 
@@ -136,7 +139,7 @@ static const struct tcs_request *get_req_from_tcs(struct 
rsc_drv *drv,
 static irqreturn_t tcs_tx_done(int irq, void *p)
 {
struct rsc_drv *drv = p;
-   int i, j;
+   int i, j, err;
unsigned long irq_status;
const struct tcs_request *req;
struct tcs_cmd *cmd;
@@ -150,6 +153,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
goto skip;
}
 
+   err = 0;
for (j = 0; j < req->num_cmds; j++) {
u32 sts;
 
@@ -160,8 +164,11 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
   !(sts & CMD_STATUS_COMPL))) {
pr_err("Incomplete request: %s: addr=%#x 
data=%#x",
   drv->name, cmd->addr, cmd->data);
+   err = -EIO;
}
}
+
+   trace_rpmh_tx_done(drv, i, req, err);
 skip:
/* Reclaim the TCS */
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
@@ -195,9 +202,11 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int 
tcs_id, int cmd_id,
cmd_complete |= cmd->wait << j;
msgid = cmd_msgid;
msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
+
write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid);
write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr);
write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
+   trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
}
 
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete);
diff --git a/drivers/soc/qcom/trace-rpmh.h b/drivers/soc/qcom/trace-rpmh.h
new file mode 100644
index ..feb0cb455e37
--- /dev/null
+++ b/drivers/soc/qcom/trace-rpmh.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RPMH_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rpmh
+
+#include 
+#include "rpmh-internal.h"
+
+TRACE_EVENT(rpmh_tx_done,
+
+   TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
+
+   TP_ARGS(d, m, r, e),
+
+   TP_STRUCT__entry(
+__string(name, d->name)
+__field(int, m)
+__field(u32, addr)
+__field(u32, data)
+__field(int, err)
+   ),
+
+   TP_fast_assign(
+  __assign_str(name, d->name);
+  __entry->m = m;
+  __entry->addr = r->cmds[0].addr;
+  __entry->data = r->cmds[0].data;
+  __entry->err = e;
+   ),
+
+   TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
+ __get_str(name), __entry->m, __entry->addr, __entry->data,
+ __entry->err)
+);
+
+TRACE_EVENT(rpmh_send_msg,
+
+   TP_PROTO(struct rsc_drv *d, int m, int n, u32 h,
+const struct tcs_cmd *c),
+
+   TP_ARGS(d, m, n, h, c),
+
+   TP_STRUCT__entry(
+__string(nam

[PATCH v8 01/10] drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs

2018-05-09 Thread Lina Iyer
Add controller driver for QCOM SoCs that have hardware based shared
resource management. The hardware IP known as RSC (Resource State
Coordinator) houses multiple Direct Resource Voter (DRV) for different
execution levels. A DRV is a unique voter on the state of a shared
resource. A Trigger Control Set (TCS) is a bunch of slots that can house
multiple resource state requests, that when triggered will issue those
requests through an internal bus to the Resource Power Manager Hardened
(RPMH) blocks. These hardware blocks are capable of adjusting clocks,
voltages, etc. The resource state request from a DRV are aggregated
along with state requests from other processors in the SoC and the
aggregate value is applied on the resource.

Some important aspects of the RPMH communication -
- Requests are <addr, value> with some header information
- Multiple requests (upto 16) may be sent through a TCS, at a time
- Requests in a TCS are sent in sequence
- Requests may be fire-n-forget or completion (response expected)
- Multiple TCS from the same DRV may be triggered simultaneously
- Cannot send a request if another request for the same addr is in
  progress from the same DRV
- When all the requests from a TCS are complete, an IRQ is raised
- The IRQ handler needs to clear the TCS before it is available for
  reuse
- TCS configuration is specific to a DRV
- Platform drivers may use DRV from different RSCs to make requests

Resource state requests made when CPUs are active are called 'active'
state requests. Requests made when all the CPUs are powered down (idle
state) are called 'sleep' state requests. They are matched by a
corresponding 'wake' state requests which puts the resources back in to
previously requested active state before resuming any CPU. TCSes are
dedicated for each type of requests. Active mode TCSes (AMC) are used to
send requests immediately to the resource, while control TCS are used to
provide specific information to the controller. Sleep and Wake TCS send
sleep and wake requests, after and before the system halt respectively.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v8:
- introduce interrupt description in DT for all DRvs

Changes in v7:
- rename 'm' and 'n' variable names

Changes in v6:
- Remove tasklet and response object
- introduce rpm_write_tcs_cmd() function
- rename tcs_irq_handler()
- avoid bool in structures. Fix tcs.h.
Changes in v4:
- lots of variable name changes as suggested by Stephen B
- use of const for data pointers
- fix comments and other code syntax
- use of bitmap for tcs_in_use instead of atomic
---
 drivers/soc/qcom/Kconfig|  10 +
 drivers/soc/qcom/Makefile   |   1 +
 drivers/soc/qcom/rpmh-internal.h|  69 
 drivers/soc/qcom/rpmh-rsc.c | 483 
 include/dt-bindings/soc/qcom,rpmh-rsc.h |  14 +
 include/soc/qcom/tcs.h  |  56 +++
 6 files changed, 633 insertions(+)
 create mode 100644 drivers/soc/qcom/rpmh-internal.h
 create mode 100644 drivers/soc/qcom/rpmh-rsc.c
 create mode 100644 include/dt-bindings/soc/qcom,rpmh-rsc.h
 create mode 100644 include/soc/qcom/tcs.h

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5c4535b545cc..1887e1b1f43b 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -56,6 +56,16 @@ config QCOM_RMTFS_MEM
 
  Say y here if you intend to boot the modem remoteproc.
 
+config QCOM_RPMH
+   bool "Qualcomm RPM-Hardened (RPMH) Communication"
+   depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
+   help
+ Support for communication with the hardened-RPM blocks in
+ Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
+ internal bus to transmit state requests for shared resources. A set
+ of hardware components aggregate requests for these resources and
+ help apply the aggregated state on the resource.
+
 config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index dcebf2814e6d..39d3a059ee50 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_QCOM_PM)   +=  spm.o
 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
 qmi_helpers-y  += qmi_encdec.o qmi_interface.o
 obj-$(CONFIG_QCOM_RMTFS_MEM)   += rmtfs_mem.o
+obj-$(CONFIG_QCOM_RPMH)+=  rpmh-rsc.o
 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
 obj-$(CONFIG_QCOM_SMEM) += smem.o
 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
new file mode 100644
index ..cc29176f1303
--- /dev/null
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright

[PATCH v8 08/10] drivers: qcom: rpmh: allow requests to be sent asynchronously

2018-05-09 Thread Lina Iyer
Platform drivers that want to send a request but do not want to block
until the RPMH request completes have now a new API -
rpmh_write_async().

The API allocates memory and send the requests and returns the control
back to the platform driver. The tx_done callback from the controller is
handled in the context of the controller's thread and frees the
allocated memory. This API allows RPMH requests from atomic contexts as
well.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v6:
- replace rpmh_client with device *
---
 drivers/soc/qcom/rpmh.c | 52 +
 include/soc/qcom/rpmh.h |  7 ++
 2 files changed, 59 insertions(+)

diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 23fcbd9487cd..1bb62876795c 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -33,6 +33,7 @@
.cmd = { { 0 } },   \
.completion = q,\
.dev = dev, \
+   .free = NULL,   \
}
 
 /**
@@ -58,6 +59,7 @@ struct cache_req {
  * @completion: triggered when request is done
  * @dev: the device making the request
  * @err: err return from the controller
+ * @free: the request object to be freed at tx_done
  */
 struct rpmh_request {
struct tcs_request msg;
@@ -65,6 +67,7 @@ struct rpmh_request {
struct completion *completion;
const struct device *dev;
int err;
+   struct rpmh_request *free;
 };
 
 /**
@@ -137,6 +140,8 @@ void rpmh_tx_done(const struct tcs_request *msg, int r)
dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n",
rpm_msg->msg.cmds[0].addr, r);
 
+   kfree(rpm_msg->free);
+
/* Signal the blocking thread we are done */
if (compl)
complete(compl);
@@ -248,6 +253,53 @@ static int __rpmh_write(const struct device *dev, enum 
rpmh_state state,
return ret;
 }
 
+static struct rpmh_request *__get_rpmh_msg_async(enum rpmh_state state,
+const struct tcs_cmd *cmd,
+u32 n)
+{
+   struct rpmh_request *req;
+
+   if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
+   return ERR_PTR(-EINVAL);
+
+   req = kzalloc(sizeof(*req), GFP_ATOMIC);
+   if (!req)
+   return ERR_PTR(-ENOMEM);
+
+   memcpy(req->cmd, cmd, n * sizeof(*cmd));
+
+   req->msg.state = state;
+   req->msg.cmds = req->cmd;
+   req->msg.num_cmds = n;
+   req->free = req;
+
+   return req;
+}
+
+/**
+ * rpmh_write_async: Write a set of RPMH commands
+ *
+ * @dev: The device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The number of elements in payload
+ *
+ * Write a set of RPMH commands, the order of commands is maintained
+ * and will be sent as a single shot.
+ */
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+const struct tcs_cmd *cmd, u32 n)
+{
+   struct rpmh_request *rpm_msg;
+
+   rpm_msg = __get_rpmh_msg_async(state, cmd, n);
+   if (IS_ERR(rpm_msg))
+   return PTR_ERR(rpm_msg);
+
+   return __rpmh_write(dev, state, rpm_msg);
+}
+EXPORT_SYMBOL(rpmh_write_async);
+
 /**
  * rpmh_write: Write a set of RPMH commands and block until response
  *
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index 42e62a0d26d8..1161a5c77e75 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -14,6 +14,9 @@
 int rpmh_write(const struct device *dev, enum rpmh_state state,
   const struct tcs_cmd *cmd, u32 n);
 
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+const struct tcs_cmd *cmd, u32 n);
+
 int rpmh_flush(const struct device *dev);
 
 int rpmh_invalidate(const struct device *dev);
@@ -24,6 +27,10 @@ static inline int rpmh_write(const struct device *dev, enum 
rpmh_state state,
 const struct tcs_cmd *cmd, u32 n)
 { return -ENODEV; }
 
+static inline int rpmh_write_async(const struct device *dev,
+  enum rpmh_state state,
+  const struct tcs_cmd *cmd, u32 n)
+{ return -ENODEV; }
 
 static inline int rpmh_flush(const struct device *dev)
 { return -ENODEV; }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v8 02/10] dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs

2018-05-09 Thread Lina Iyer
Add device binding documentation for Qualcomm Technology Inc's RPMH RSC
driver. The driver is used for communicating resource state requests for
shared resources.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Rob Herring <r...@kernel.org>
---
Changes in v8:
- Describe IRQ for all DRVs

Changes in v7:
- Fix example

Changes in v6:
- Address comments from Stephen Boyd

Changes in v3:
- Move to soc/qcom
- Amend text per Stephen's suggestions

Changes in v2:
- Amend text to describe the registers in reg property
- Add reg-names for the registers
- Update examples to use GIC_SPI in interrupts instead of 0
- Rephrase incorrect description

Changes in v3:
- Fix unwanted capitalization
- Remove clients from the examples, this doc does not describe
  them
- Rephrase introductory paragraph
- Remove hardware specifics from DT bindings
---
 .../devicetree/bindings/soc/qcom/rpmh-rsc.txt | 137 ++
 1 file changed, 137 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt

diff --git a/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt 
b/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt
new file mode 100644
index ..e15c100f5c92
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt
@@ -0,0 +1,137 @@
+RPMH RSC:
+
+
+Resource Power Manager Hardened (RPMH) is the mechanism for communicating with
+the hardened resource accelerators on Qualcomm SoCs. Requests to the resources
+can be written to the Trigger Command Set (TCS)  registers and using a (addr,
+val) pair and triggered. Messages in the TCS are then sent in sequence over an
+internal bus.
+
+The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity
+(Resource State Coordinator a.k.a RSC) that can handle multiple sleep and
+active/wake resource requests. Multiple such DRVs can exist in a SoC and can
+be written to from Linux. The structure of each DRV follows the same template
+with a few variations that are captured by the properties here.
+
+A TCS may be triggered from Linux or triggered by the F/W after all the CPUs
+have powered off to facilitate idle power saving. TCS could be classified as -
+
+   SLEEP   /* Triggered by F/W */
+   WAKE/* Triggered by F/W */
+   ACTIVE  /* Triggered by Linux */
+   CONTROL /* Triggered by F/W */
+
+The order in which they are described in the DT, should match the hardware
+configuration.
+
+Requests can be made for the state of a resource, when the subsystem is active
+or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state
+will be an aggregate of the sleep votes from each of those subsystems. Clients
+may request a sleep value for their shared resources in addition to the active
+mode requests.
+
+Properties:
+
+- compatible:
+   Usage: required
+   Value type: 
+   Definition: Should be "qcom,rpmh-rsc".
+
+- reg:
+   Usage: required
+   Value type: 
+   Definition: The first register specifies the base address of the
+   DRV(s). The number of DRVs in the dependent on the RSC.
+   The tcs-offset specifies the start address of the
+   TCS in the DRVs.
+
+- reg-names:
+   Usage: required
+   Value type: 
+   Definition: Maps the register specified in the reg property. Must be
+   "drv-0", "drv-1", "drv-2" etc and "tcs-offset". The
+
+- interrupts:
+   Usage: required
+   Value type: 
+   Definition: The interrupt that trips when a message complete/response
+  is received for this DRV from the accelerators.
+
+- qcom,drv-id:
+   Usage: required
+   Value type: 
+   Definition: The id of the DRV in the RSC block that will be used by
+   this controller.
+
+- qcom,tcs-config:
+   Usage: required
+   Value type: 
+   Definition: The tuple defining the configuration of TCS.
+   Must have 2 cells which describe each TCS type.
+   .
+   The order of the TCS must match the hardware
+   configuration.
+   - Cell #1 (TCS Type): TCS types to be specified -
+   SLEEP_TCS
+   WAKE_TCS
+   ACTIVE_TCS
+   CONTROL_TCS
+   - Cell #2 (Number of TCS): 
+
+- label:
+   Usage: optional
+   Value type: 
+   Definition: Name for the RSC. The name would be used in trace logs.
+
+Drivers that want to use the RSC to communicate with RPMH must specify their
+bindings as child nodes of the RSC controllers they wish to communicate with.
+
+Example 1:
+
+For a TCS whose RSC base address is is 0x179C and is at a DRV id of 2, the
+register offsets for DRV2 s

[PATCH v8 06/10] drivers: qcom: rpmh-rsc: allow invalidation of sleep/wake TCS

2018-05-09 Thread Lina Iyer
Allow sleep and wake commands to be cleared from the respective TCSes,
so that they can be re-populated.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- Move bitmap_zero() outside the loop

Changes in v6:
- remove unnecessary locks around __tcs_invalidate
- rename function to tcs_invaldiate

Changes in v4:
- refactored the rphm_rsc_invalidate()
---
 drivers/soc/qcom/rpmh-rsc.c | 45 +
 1 file changed, 45 insertions(+)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index b5894b001ae1..68c25ebbbe09 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -104,6 +104,51 @@ static struct tcs_group *get_tcs_of_type(struct rsc_drv 
*drv, int type)
return >tcs[type];
 }
 
+static int tcs_invalidate(struct rsc_drv *drv, int type)
+{
+   int m;
+   struct tcs_group *tcs;
+
+   tcs = get_tcs_of_type(drv, type);
+   if (IS_ERR(tcs))
+   return PTR_ERR(tcs);
+
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
+   spin_unlock(>lock);
+   return 0;
+   }
+
+   for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
+   if (!tcs_is_free(drv, m)) {
+   spin_unlock(>lock);
+   return -EAGAIN;
+   }
+   write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
+   }
+   bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
+   spin_unlock(>lock);
+
+   return 0;
+}
+
+/**
+ * rpmh_rsc_invalidate - Invalidate sleep and wake TCSes
+ *
+ * @drv: the RSC controller
+ */
+int rpmh_rsc_invalidate(struct rsc_drv *drv)
+{
+   int ret;
+
+   ret = tcs_invalidate(drv, SLEEP_TCS);
+   if (!ret)
+   ret = tcs_invalidate(drv, WAKE_TCS);
+
+   return ret;
+}
+EXPORT_SYMBOL(rpmh_rsc_invalidate);
+
 static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
 const struct tcs_request *msg)
 {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v8 04/10] drivers: qcom: rpmh: add RPMH helper functions

2018-05-09 Thread Lina Iyer
Sending RPMH requests and waiting for response from the controller
through a callback is common functionality across all platform drivers.
To simplify drivers, add a library functions to create RPMH client and
send resource state requests.

rpmh_write() is a synchronous blocking call that can be used to send
active state requests.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- Optimization and locking fixes

Changes in v6:
- replace rpmh_client with device
- inline wait_for_tx_done()

Changes in v4:
- use const struct tcs_cmd in API
- remove wait count from this patch
- changed -EFAULT to -EINVAL
---
 drivers/soc/qcom/Makefile|   4 +-
 drivers/soc/qcom/rpmh-internal.h |   6 ++
 drivers/soc/qcom/rpmh-rsc.c  |   8 ++
 drivers/soc/qcom/rpmh.c  | 176 +++
 include/soc/qcom/rpmh.h  |  25 +
 5 files changed, 218 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/qcom/rpmh.c
 create mode 100644 include/soc/qcom/rpmh.h

diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index cb6300f6a8e9..bb395c3202ca 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -7,7 +7,9 @@ obj-$(CONFIG_QCOM_PM)   +=  spm.o
 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
 qmi_helpers-y  += qmi_encdec.o qmi_interface.o
 obj-$(CONFIG_QCOM_RMTFS_MEM)   += rmtfs_mem.o
-obj-$(CONFIG_QCOM_RPMH)+=  rpmh-rsc.o
+obj-$(CONFIG_QCOM_RPMH)+= qcom_rpmh.o
+qcom_rpmh-y+= rpmh-rsc.o
+qcom_rpmh-y+= rpmh.o
 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
 obj-$(CONFIG_QCOM_SMEM) += smem.o
 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index cc29176f1303..d9a21726e568 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -14,6 +14,7 @@
 #define MAX_CMDS_PER_TCS   16
 #define MAX_TCS_PER_TYPE   3
 #define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define RPMH_MAX_CTRLR 2
 
 struct rsc_drv;
 
@@ -52,6 +53,7 @@ struct tcs_group {
  * @tcs:TCS groups
  * @tcs_in_use: s/w state of the TCS
  * @lock:   synchronize state of the controller
+ * @list:   element in list of drv
  */
 struct rsc_drv {
const char *name;
@@ -61,9 +63,13 @@ struct rsc_drv {
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
+   struct list_head list;
 };
 
+extern struct list_head rsc_drv_list;
 
 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
 
+void rpmh_tx_done(const struct tcs_request *msg, int r);
+
 #endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 0a8cec9d1651..c0edf3850147 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -61,6 +61,8 @@
 #define CMD_STATUS_ISSUED  BIT(8)
 #define CMD_STATUS_COMPL   BIT(16)
 
+LIST_HEAD(rsc_drv_list);
+
 static u32 read_tcs_reg(struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
 {
return readl_relaxed(drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id +
@@ -176,6 +178,8 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
spin_lock(>lock);
clear_bit(i, drv->tcs_in_use);
spin_unlock(>lock);
+   if (req)
+   rpmh_tx_done(req, err);
}
 
return IRQ_HANDLED;
@@ -469,6 +473,10 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
/* Enable the active TCS to send requests immediately */
write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask);
 
+   INIT_LIST_HEAD(>list);
+   list_add(>list, _drv_list);
+   dev_set_drvdata(>dev, drv);
+
return devm_of_platform_populate(>dev);
 }
 
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
new file mode 100644
index ..74bb82339b01
--- /dev/null
+++ b/drivers/soc/qcom/rpmh.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "rpmh-internal.h"
+
+#define RPMH_TIMEOUT_MSmsecs_to_jiffies(1)
+
+#define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name)   \
+   struct rpmh_request name = {\
+   .msg = {\
+   .state = s, \
+   .cmds = name.cmd,   \
+   .num_cmds = 0,  \
+  

[PATCH v8 00/10] drivers/qcom: add RPMH communication support

2018-05-09 Thread Lina Iyer
Changes in v8:
- Bounds check for cmd_cache
- Describe interrupts to other DRVs in DT bindings
- Rebase on top of 4.17-rc3

Changes in v7:
- Rename 'm' and 'n' and use tcs_id and cmd_id instead
- Bug fix in find_match() and other review comments from Matthias
- Spinlock around get_rpmh_ctrlr()
- DT documentation example fixes
- Rebase on top of 4.16-rc2

Changes in v6:
- Remove tasklet in rpmh-rsc.c
- Remove rpmh_client and use struct device * instead
- Variable changes and bug fixes
- DT binding changes to describe all DRVs in the RSC
- Documentation and comment fixes

Changes in v5:
- Add Reviewed-by tags
- Rebase on top of 4.16

Changes in v4:
- Rename variables as suggested by Stephen and Evan
- Lot of minor syntax and style fixes
- Fix FTRACE compilation error
- Improve doc comments and DT description

Changes in v3:
- Address Steven's comments in FTRACE
- Fix DT documentation as suggested by Rob H
- Fix error handling in IRQ handler as suggested by Evan
- Remove locks in rpmh_flush()
- Improve comments

Changes in v2:
- Added sleep/wake, async and batch requests support
- Addressed Bjorn's comments
- Private FTRACE for drivers/soc/qcom as suggested by Steven
- Sparse checked on these patches
- Use SPDX license commenting sytle

This set of patches add the ability for platform drivers to make use of shared
resources in newer Qualcomm SoCs like SDM845. Resources that are shared between
multiple processors in a SoC are generally controlled by a dedicated remote
processor. The remote processor (Resource Power Manager or RPM in previous QCOM
SoCs) receives requests for resource state from other processors using the
shared resource, aggregates the request and applies the result on the shared
resource. SDM845 advances this concept and uses h/w (hardened I/P) blocks for
aggregating requests and applying the result on the resource. The resources
could be clocks, regulators or bandwidth requests for buses. This new
architecture is called RPM-hardened or RPMH in short.

Since this communication mechanism is completely hardware driven without a
processor intervention on the remote end, existing mechanisms like RPM-SMD are
no longer useful. Also, there is no serialization of data or is data is written
to a shared memory in this new format. The data used is different, unsigned 32
bits are used for representing an address, data and header. Each resource's
property is a unique u32 address and have pre-defined set of property specific
valid values. A request that comprises of <header, addr, data> is sent by
writing to a set of registers from Linux and transmitted to the remote slave
through an internal bus. The remote end aggregates this request along with
requests from other processors for the  and applies the result.

The hardware block that houses this functionality is called Resource State
Coordinator or RSC. Inside the RSC are set of slots for sending RPMH requests
called Trigger Commands Sets (TCS). The set of patches are for writing the
requests into these TCSes and sending them to hardened IP blocks.

The driver design is split into two components. The RSC driver housed in
rpmh-rsc.c and the set of library functions in rpmh.c that frame the request and
transmit it using the controller. This first set of patches allow a simple
synchronous request to be made by the platform drivers. Future patches will add
more functionality that cater to complex drivers and use cases.

Please consider reviewing this patchset.

v1: https://www.spinics.net/lists/devicetree/msg210980.html
v2: https://lkml.org/lkml/2018/2/15/852
v3: https://lkml.org/lkml/2018/3/2/801
v4: https://lkml.org/lkml/2018/3/9/979
v5: https://lkml.org/lkml/2018/4/5/480
v6: https://lkml.org/lkml/2018/4/19/914
v7: https://lkml.org/lkml/2018/5/2/779

Lina Iyer (10):
  drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
  dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
  drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
  drivers: qcom: rpmh: add RPMH helper functions
  drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS
  drivers: qcom: rpmh-rsc: allow invalidation of sleep/wake TCS
  drivers: qcom: rpmh: cache sleep/wake state requests
  drivers: qcom: rpmh: allow requests to be sent asynchronously
  drivers: qcom: rpmh: add support for batch RPMH request
  drivers: qcom: rpmh-rsc: allow active requests from wake TCS

 .../devicetree/bindings/soc/qcom/rpmh-rsc.txt | 137 
 drivers/soc/qcom/Kconfig  |  10 +
 drivers/soc/qcom/Makefile |   4 +
 drivers/soc/qcom/rpmh-internal.h  |  83 +++
 drivers/soc/qcom/rpmh-rsc.c   | 683 ++
 drivers/soc/qcom/rpmh.c   | 585 +++
 drivers/soc/qcom/trace-rpmh.h |  82 +++
 include/dt-bindings/soc/qcom,rpmh-rsc.h   |  14 +
 include/soc/qcom/rpmh.h   |  51 ++
 include/soc/qcom/tcs.h|  56 ++
 10 files changed, 1705 inse

Re: [PATCH v6 05/10] drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS

2018-04-27 Thread Lina Iyer

On Wed, Apr 25 2018 at 15:41 -0600, Matthias Kaehlcke wrote:

On Thu, Apr 19, 2018 at 04:16:30PM -0600, Lina Iyer wrote:

Sleep and wake requests are sent when the application processor
subsystem of the SoC is entering deep sleep states like in suspend.
These requests help lower the system power requirements when the
resources are not in use.

Sleep and wake requests are written to the TCS slots but are not
triggered at the time of writing. The TCS are triggered by the firmware
after the last of the CPUs has executed its WFI. Since these requests
may come in different batches of requests, it is the job of this
controller driver to find and arrange the requests into the available
TCSes.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Evan Green <evgr...@chromium.org>
---
 drivers/soc/qcom/rpmh-internal.h |   8 +++
 drivers/soc/qcom/rpmh-rsc.c  | 120 +++
 2 files changed, 128 insertions(+)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index d9a21726e568..6e19fe458c31 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h





+static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd,
+ int len)
+{
+   int i, j;
+
+   /* Check for already cached commands */
+   for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
+   for (j = 0; j < len; j++) {
+   if (tcs->cmd_cache[i] != cmd[0].addr) {


Shouldn't the condition be 'tcs->cmd_cache[i + j] != cmd[j].addr'?


Here, we are trying to find the first address from the request and its
position 'i' in the cmd_cache.


Otherwise the code below the following if branch will never be
executed. Either the 'tcs->cmd_cache[i] != cmd[0].addr' branch isn't
entered because the addresses match, or the addresses don't match
and the inner loop is aborted after the first iteration.


+   if (j == 0)
+   break;
+   WARN(tcs->cmd_cache[i + j] != cmd[j].addr,
+"Message does not match previous 
sequence.\n");

We now check for the sequence using the iterator 'j' only after we have
found 'i' (the beginning of our request).

I hope that helps clear the concern.

-- Lina


+   return -EINVAL;
+   } else if (j == len - 1) {
+   return i;
+   }
+   }
+   }
+
+   return -ENODATA;
+}


Re: [PATCH v6 05/10] drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS

2018-04-27 Thread Lina Iyer

On Fri, Apr 27 2018 at 12:40 -0600, Matthias Kaehlcke wrote:

On Fri, Apr 27, 2018 at 11:39:43AM -0600, Lina Iyer wrote:

On Wed, Apr 25 2018 at 15:41 -0600, Matthias Kaehlcke wrote:
> On Thu, Apr 19, 2018 at 04:16:30PM -0600, Lina Iyer wrote:
> > Sleep and wake requests are sent when the application processor
> > subsystem of the SoC is entering deep sleep states like in suspend.
> > These requests help lower the system power requirements when the
> > resources are not in use.
> >
> > Sleep and wake requests are written to the TCS slots but are not
> > triggered at the time of writing. The TCS are triggered by the firmware
> > after the last of the CPUs has executed its WFI. Since these requests
> > may come in different batches of requests, it is the job of this
> > controller driver to find and arrange the requests into the available
> > TCSes.
> >
> > Signed-off-by: Lina Iyer <il...@codeaurora.org>
> > Reviewed-by: Evan Green <evgr...@chromium.org>
> > ---
> >  drivers/soc/qcom/rpmh-internal.h |   8 +++
> >  drivers/soc/qcom/rpmh-rsc.c  | 120 +++
> >  2 files changed, 128 insertions(+)
> >
> > diff --git a/drivers/soc/qcom/rpmh-internal.h 
b/drivers/soc/qcom/rpmh-internal.h
> > index d9a21726e568..6e19fe458c31 100644
> > --- a/drivers/soc/qcom/rpmh-internal.h
> > +++ b/drivers/soc/qcom/rpmh-internal.h
>
> 
>
> > +static int find_match(const struct tcs_group *tcs, const struct tcs_cmd 
*cmd,
> > +   int len)
> > +{
> > + int i, j;
> > +
> > + /* Check for already cached commands */
> > + for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
> > + for (j = 0; j < len; j++) {
> > + if (tcs->cmd_cache[i] != cmd[0].addr) {
>
> Shouldn't the condition be 'tcs->cmd_cache[i + j] != cmd[j].addr'?
>
Here, we are trying to find the first address from the request and its
position 'i' in the cmd_cache.

> Otherwise the code below the following if branch will never be
> executed. Either the 'tcs->cmd_cache[i] != cmd[0].addr' branch isn't
> entered because the addresses match, or the addresses don't match
> and the inner loop is aborted after the first iteration.
>
> > + if (j == 0)
> > + break;
> > + WARN(tcs->cmd_cache[i + j] != cmd[j].addr,
> > +  "Message does not match previous 
sequence.\n");
We now check for the sequence using the iterator 'j' only after we have
found 'i' (the beginning of our request).

I hope that helps clear the concern.


It doesn't, maybe I'm just confused, the driver has a certain
complexity and I don't claim to have a comprehensive understanding :)

If I understand correctly find_match() is used to find a sequence of
commands of length 'len' in the command cache. If that is correct I
would expect it to do the following:

1. iterate through the commands in the command cache and find a
command that matches the first command in the sequence

2. verify that the (len - 1) subsequent commands match those in the
sequence, otherwise bail out

If I'm not mistaken the current version of find_match() only checks
that the first command exists. After that it happily increases the
command index, but doesn't perform any checks (after finding the first
command 'tcs->cmd_cache[i] != cmd[0].addr' remains false for the
subsequent values of j). When j reaches (len - 1) the function
returns the index of the first command in the cache, regardless of
whether the other commands match or not.


Did you miss the check inside the WARN?
WARN(tcs->cmd_cache[i + j] != cmd[j].addr,

--Lina



Re: [PATCH v6 09/10] drivers: qcom: rpmh: add support for batch RPMH request

2018-04-27 Thread Lina Iyer

On Wed, Apr 25 2018 at 17:41 -0600, Matthias Kaehlcke wrote:

On Thu, Apr 19, 2018 at 04:16:34PM -0600, Lina Iyer wrote:

Platform drivers need make a lot of resource state requests at the same
time, say, at the start or end of an usecase. It can be quite
inefficient to send each request separately. Instead they can give the
RPMH library a batch of requests to be sent and wait on the whole
transaction to be complete.

rpmh_write_batch() is a blocking call that can be used to send multiple
RPMH command sets. Each RPMH command set is set asynchronously and the
API blocks until all the command sets are complete and receive their
tx_done callbacks.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v6:
- replace rpmh_client with device *
Changes in v4:
- reorganize rpmh_write_batch()
- introduce wait_count here, instead of patch#4
---
 drivers/soc/qcom/rpmh.c | 155 +++-
 include/soc/qcom/rpmh.h |   8 +++
 2 files changed, 161 insertions(+), 2 deletions(-)







+static int cache_batch(struct rpmh_ctrlr *ctrlr,
+  struct rpmh_request **rpm_msg, int count)
+{
+   unsigned long flags;
+   int ret = 0;
+   int index = 0;
+   int i;
+
+   spin_lock_irqsave(>lock, flags);
+   while (ctrlr->batch_cache[index])
+   index++;


This will access memory beyond 'batch_cache' when the cache is full.


Ok. Will check for index.





+static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
+{
+   unsigned long flags;
+   int index = 0;
+   int i;
+
+   spin_lock_irqsave(>lock, flags);
+   while (ctrlr->batch_cache[index])
+   index++;


Same as above. Also, why loop twice?


Good idea. Will fix.


+   for (i = 0; i < index; i++) {
+   kfree(ctrlr->batch_cache[i]->free);
+   ctrlr->batch_cache[i] = NULL;
+   }





+/**
+ * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
+ * batch to finish.
+ *
+ * @dev: the device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The array of count of elements in each batch, 0 terminated.


nit: in this driver 'n' is usually associated with the command offset
within a TCS. Since it isn't an overly descriptive name it may already
cost the reader a while to commit that to his/her memory, and now
we are overloading 'n' with a different meaning (I also noticed this in
another patch of this series, but didn't comment).


Sure, will change the variable name here.


/*
 * Nobody else should be calling this function other than system PM,,

   ~
Remove extra comma.

OK.

Thanks,
Lina



Re: [PATCH v6 04/10] drivers: qcom: rpmh: add RPMH helper functions

2018-04-27 Thread Lina Iyer

On Thu, Apr 26 2018 at 12:05 -0600, Matthias Kaehlcke wrote:

Hi Lina,

On Thu, Apr 19, 2018 at 04:16:29PM -0600, Lina Iyer wrote:

Sending RPMH requests and waiting for response from the controller
through a callback is common functionality across all platform drivers.
To simplify drivers, add a library functions to create RPMH client and
send resource state requests.

rpmh_write() is a synchronous blocking call that can be used to send
active state requests.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v6:
- replace rpmh_client with device
- inline wait_for_tx_done()

Changes in v4:
- use const struct tcs_cmd in API
- remove wait count from this patch
- changed -EFAULT to -EINVAL
---
 drivers/soc/qcom/Makefile|   4 +-
 drivers/soc/qcom/rpmh-internal.h |   6 ++
 drivers/soc/qcom/rpmh-rsc.c  |   8 ++
 drivers/soc/qcom/rpmh.c  | 168 +++
 include/soc/qcom/rpmh.h  |  25 +
 5 files changed, 210 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/qcom/rpmh.c
 create mode 100644 include/soc/qcom/rpmh.h

diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index cb6300f6a8e9..bb395c3202ca 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -7,7 +7,9 @@ obj-$(CONFIG_QCOM_PM)   +=  spm.o
 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
 qmi_helpers-y  += qmi_encdec.o qmi_interface.o
 obj-$(CONFIG_QCOM_RMTFS_MEM)   += rmtfs_mem.o
-obj-$(CONFIG_QCOM_RPMH)+=  rpmh-rsc.o
+obj-$(CONFIG_QCOM_RPMH)+= qcom_rpmh.o
+qcom_rpmh-y+= rpmh-rsc.o
+qcom_rpmh-y+= rpmh.o
 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
 obj-$(CONFIG_QCOM_SMEM) += smem.o
 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index cc29176f1303..d9a21726e568 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -14,6 +14,7 @@
 #define MAX_CMDS_PER_TCS   16
 #define MAX_TCS_PER_TYPE   3
 #define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define RPMH_MAX_CTRLR 2

 struct rsc_drv;

@@ -52,6 +53,7 @@ struct tcs_group {
  * @tcs:TCS groups
  * @tcs_in_use: s/w state of the TCS
  * @lock:   synchronize state of the controller
+ * @list:   element in list of drv
  */
 struct rsc_drv {
const char *name;
@@ -61,9 +63,13 @@ struct rsc_drv {
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
+   struct list_head list;
 };

+extern struct list_head rsc_drv_list;

 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);

+void rpmh_tx_done(const struct tcs_request *msg, int r);

   ~

nit: consider using a more expressive name, like status, rc, res or
err.


OK. Will fix.





+static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
+{
+   int i;
+   struct rsc_drv *p, *drv = dev_get_drvdata(dev->parent);
+   struct rpmh_ctrlr *ctrlr = ERR_PTR(-EINVAL);
+
+   if (!drv)
+   return ctrlr;
+
+   for (i = 0; i < RPMH_MAX_CTRLR; i++) {
+   if (rpmh_rsc[i].drv == drv) {
+   ctrlr = _rsc[i];
+   return ctrlr;
+   }
+   }
+
+   list_for_each_entry(p, _drv_list, list) {
+   if (drv == p) {
+   for (i = 0; i < RPMH_MAX_CTRLR; i++) {
+   if (!rpmh_rsc[i].drv)
+   break;
+   }
+   rpmh_rsc[i].drv = drv;


There is a race condition, get_rpmh_ctrlr() could be executed
simulatenously in different contexts, and select the same
controller instance for different DRVs.


True. This will need to be serialized.


It's probably an unlikely case, but to be safe you'd have to do
something like this:

retry:
for (i = 0; i < RPMH_MAX_CTRLR; i++) {
if (!rpmh_rsc[i].drv)
break;
}

spin_lock(_rsc[i].lock);

if (!rpmh_rsc[i].drv) {
rpmh_rsc[i].drv = drv;
ctrlr = _rsc[i];
} else {
spin_unlock(_rsc[i].lock);
goto retry;
}

spin_unlock(_rsc[i].lock);


The above code doesn't address another potential error case, where
#DRV > RPMH_MAX_CTRLR. In this case we'd access memory beyond
rpmh_rsc. This would be a configuration error, not sure if it's
strictly necessary to handle it.


I think I might be able to solve for this a bit simpler with another
spinlock for the rpmh_rsc.





+/**
+ * rpmh_write: Write a set of RPMH commands and block until response
+ *
+ * @rc: The RPMh handle got from rpmh_get_client

  

nit: Other than this the driver consistently uses 'RPMH'


OK.

Thanks for the review Matthias.

-- Lina



Re: [PATCH v6 06/10] drivers: qcom: rpmh-rsc: allow invalidation of sleep/wake TCS

2018-04-27 Thread Lina Iyer

On Wed, Apr 25 2018 at 16:11 -0600, Matthias Kaehlcke wrote:

On Thu, Apr 19, 2018 at 04:16:31PM -0600, Lina Iyer wrote:

Allow sleep and wake commands to be cleared from the respective TCSes,
so that they can be re-populated.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v6:
- remove unnecessary locks around __tcs_invalidate
- rename function to tcs_invaldiate

Changes in v4:
- refactored the rphm_rsc_invalidate()
---
 drivers/soc/qcom/rpmh-rsc.c | 45 +
 1 file changed, 45 insertions(+)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index d169f7da5422..170d4a10275d 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -101,6 +101,51 @@ static struct tcs_group *get_tcs_of_type(struct rsc_drv 
*drv, int type)
return >tcs[type];
 }

+static int tcs_invalidate(struct rsc_drv *drv, int type)
+{
+   int m;
+   struct tcs_group *tcs;
+
+   tcs = get_tcs_of_type(drv, type);
+   if (IS_ERR(tcs))
+   return PTR_ERR(tcs);
+
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
+   spin_unlock(>lock);
+   return 0;
+   }
+
+   for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
+   if (!tcs_is_free(drv, m)) {
+   spin_unlock(>lock);
+   return -EAGAIN;
+   }
+   write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
+   bitmap_zero(tcs->slots, MAX_TCS_SLOTS);


Shouldn't this only clear the slots corresponding to 'm'?

If resetting the entire bitmap is really intended it could be done
once after the loop, though the bitmap might be left in an
inconsistent state if a TCS is still in use.

The TCS will not be in use, the check tcs_is_free() will ensure that. I
will move the bitmap_zero() outside the for().

Thanks,
Lina



Re: [PATCH v6 05/10] drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS

2018-04-27 Thread Lina Iyer

On Fri, Apr 27 2018 at 14:06 -0600, Matthias Kaehlcke wrote:

On Fri, Apr 27, 2018 at 01:45:59PM -0600, Lina Iyer wrote:

On Fri, Apr 27 2018 at 12:40 -0600, Matthias Kaehlcke wrote:
> On Fri, Apr 27, 2018 at 11:39:43AM -0600, Lina Iyer wrote:
> > On Wed, Apr 25 2018 at 15:41 -0600, Matthias Kaehlcke wrote:
> > > On Thu, Apr 19, 2018 at 04:16:30PM -0600, Lina Iyer wrote:
> > > > Sleep and wake requests are sent when the application processor
> > > > subsystem of the SoC is entering deep sleep states like in suspend.
> > > > These requests help lower the system power requirements when the
> > > > resources are not in use.
> > > >
> > > > Sleep and wake requests are written to the TCS slots but are not
> > > > triggered at the time of writing. The TCS are triggered by the firmware
> > > > after the last of the CPUs has executed its WFI. Since these requests
> > > > may come in different batches of requests, it is the job of this
> > > > controller driver to find and arrange the requests into the available
> > > > TCSes.
> > > >
> > > > Signed-off-by: Lina Iyer <il...@codeaurora.org>
> > > > Reviewed-by: Evan Green <evgr...@chromium.org>
> > > > ---
> > > >  drivers/soc/qcom/rpmh-internal.h |   8 +++
> > > >  drivers/soc/qcom/rpmh-rsc.c  | 120 +++
> > > >  2 files changed, 128 insertions(+)
> > > >
> > > > diff --git a/drivers/soc/qcom/rpmh-internal.h 
b/drivers/soc/qcom/rpmh-internal.h
> > > > index d9a21726e568..6e19fe458c31 100644
> > > > --- a/drivers/soc/qcom/rpmh-internal.h
> > > > +++ b/drivers/soc/qcom/rpmh-internal.h
> > >
> > > 
> > >
> > > > +static int find_match(const struct tcs_group *tcs, const struct 
tcs_cmd *cmd,
> > > > + int len)
> > > > +{
> > > > +   int i, j;
> > > > +
> > > > +   /* Check for already cached commands */
> > > > +   for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
> > > > +   for (j = 0; j < len; j++) {
> > > > +   if (tcs->cmd_cache[i] != cmd[0].addr) {
> > >
> > > Shouldn't the condition be 'tcs->cmd_cache[i + j] != cmd[j].addr'?
> > >
> > Here, we are trying to find the first address from the request and its
> > position 'i' in the cmd_cache.
> >
> > > Otherwise the code below the following if branch will never be
> > > executed. Either the 'tcs->cmd_cache[i] != cmd[0].addr' branch isn't
> > > entered because the addresses match, or the addresses don't match
> > > and the inner loop is aborted after the first iteration.
> > >
> > > > +   if (j == 0)
> > > > +   break;
> > > > +   WARN(tcs->cmd_cache[i + j] != cmd[j].addr,
> > > > +"Message does not match previous 
sequence.\n");
> > We now check for the sequence using the iterator 'j' only after we have
> > found 'i' (the beginning of our request).
> >
> > I hope that helps clear the concern.
>
> It doesn't, maybe I'm just confused, the driver has a certain
> complexity and I don't claim to have a comprehensive understanding :)
>
> If I understand correctly find_match() is used to find a sequence of
> commands of length 'len' in the command cache. If that is correct I
> would expect it to do the following:
>
> 1. iterate through the commands in the command cache and find a
> command that matches the first command in the sequence
>
> 2. verify that the (len - 1) subsequent commands match those in the
> sequence, otherwise bail out
>
> If I'm not mistaken the current version of find_match() only checks
> that the first command exists. After that it happily increases the
> command index, but doesn't perform any checks (after finding the first
> command 'tcs->cmd_cache[i] != cmd[0].addr' remains false for the
> subsequent values of j). When j reaches (len - 1) the function
> returns the index of the first command in the cache, regardless of
> whether the other commands match or not.
>
Did you miss the check inside the WARN?
WARN(tcs->cmd_cache[i + j] != cmd[j].addr,


My point is that this code is never reached, also regardless of the
condition, the branch would always return -EINVAL.

for (j = 0; j < len; j++) {
if (tcs->cmd_cache[i] != cmd[0].addr) {
if (j == 0)
break;
WARN(t

Re: [PATCH v8 05/10] drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS

2018-05-10 Thread Lina Iyer

On Wed, May 09 2018 at 17:25 -0600, Matthias Kaehlcke wrote:

Hi Lina,

On Wed, May 09, 2018 at 11:01:54AM -0600, Lina Iyer wrote:

Sleep and wake requests are sent when the application processor
subsystem of the SoC is entering deep sleep states like in suspend.
These requests help lower the system power requirements when the
resources are not in use.

Sleep and wake requests are written to the TCS slots but are not
triggered at the time of writing. The TCS are triggered by the firmware
after the last of the CPUs has executed its WFI. Since these requests
may come in different batches of requests, it is the job of this
controller driver to find and arrange the requests into the available
TCSes.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
Reviewed-by: Evan Green <evgr...@chromium.org>

---

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index c0edf3850147..b5894b001ae1 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c



+static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd,
+ int len)
+{
+   int i, j;
+
+   /* Check for already cached commands */
+   for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
+   if (tcs->cmd_cache[i] != cmd[0].addr)
+   continue;
+   if (i + len >= MAX_TCS_SLOTS)
+   goto seq_err;


The command cache can have less than MAX_TCS_SLOTS slot:



That's true. I forgot that I had optimized the cache slots. Thanks for
pointing out.


static int rpmh_probe_tcs_config(struct platform_device *pdev,
 struct rsc_drv *drv)
{
...
tcs->cmd_cache = devm_kcalloc(>dev,
  tcs->num_tcs * ncpt, sizeof(u32),
  GFP_KERNEL);
...
}

So the condition needs to be:

if (i + len >= tcs->num_tcs * tcs->ncpt)


+static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
+ int *tcs_id, int *cmd_id)
+{
+   int slot, offset;
+   int i = 0;
+
+   /* Find if we already have the msg in our TCS */
+   slot = find_match(tcs, msg->cmds, msg->num_cmds);
+   if (slot >= 0)
+   goto copy_data;
+
+   /* Do over, until we can fit the full payload in a TCS */
+   do {
+   slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
+ i, msg->num_cmds, 0);
+   if (slot == MAX_TCS_SLOTS)
+   return -ENOMEM;


Like above, use 'tcs->num_tcs * tcs->ncpt' as maximum instead of
MAX_TCS_SLOTS.


+static int tcs_ctrl_write(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+   struct tcs_group *tcs;
+   int tcs_id = 0, cmd_id = 0;
+   unsigned long flags;
+   int ret;
+
+   tcs = get_tcs_for_msg(drv, msg);
+   if (IS_ERR(tcs))
+   return PTR_ERR(tcs);
+
+   spin_lock_irqsave(>lock, flags);
+   /* find the m-th TCS and the n-th position in the TCS to write to */


The comment still refers to the old names 'm' and 'n'.


Really? :)
Will fix.

Thanks for your review,
Lina



Re: [PATCH v8 09/10] drivers: qcom: rpmh: add support for batch RPMH request

2018-05-10 Thread Lina Iyer

On Wed, May 09 2018 at 16:03 -0600, Matthias Kaehlcke wrote:

On Wed, May 09, 2018 at 11:01:58AM -0600, Lina Iyer wrote:

Platform drivers need make a lot of resource state requests at the same
time, say, at the start or end of an usecase. It can be quite
inefficient to send each request separately. Instead they can give the
RPMH library a batch of requests to be sent and wait on the whole
transaction to be complete.

rpmh_write_batch() is a blocking call that can be used to send multiple
RPMH command sets. Each RPMH command set is set asynchronously and the
API blocks until all the command sets are complete and receive their
tx_done callbacks.

Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- Check for loop out of bounds

Changes in v6:
- replace rpmh_client with device *
Changes in v4:
- reorganize rpmh_write_batch()
- introduce wait_count here, instead of patch#4
---
 drivers/soc/qcom/rpmh.c | 154 +++-
 include/soc/qcom/rpmh.h |   8 +++
 2 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 1bb62876795c..a0e277b4b846 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c

...

+static int flush_batch(struct rpmh_ctrlr *ctrlr)
+{
+   const struct rpmh_request *rpm_msg;
+   unsigned long flags;
+   int ret = 0;
+   int i;
+
+   /* Send Sleep/Wake requests to the controller, expect no response */
+   spin_lock_irqsave(>lock, flags);
+   for (i = 0; ctrlr->batch_cache[i]; i++) {


I missed this earlier: the loop goes beyond ctrlr->batch_cache when
the batch cache is full.


+   rpm_msg = ctrlr->batch_cache[i];
+   ret = rpmh_rsc_write_ctrl_data(ctrlr->drv, _msg->msg);
+   if (ret)
+   break;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}
+
+static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
+{
+   unsigned long flags;
+   int index = 0;
+
+   spin_lock_irqsave(>lock, flags);
+   while (ctrlr->batch_cache[index]) {


This still goes beyond ctrlr->batch_cache when the batch cache is
full.

I will check through the code for all out-of-bounds. Seems like I have
not worried about it too much. Well the space here assigned is beyond
what we see on a production device. Neverthless, it needs to be checked.

Thanks for your review Matthias.

-- Lina



Re: [PATCH v8 03/10] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE

2018-05-10 Thread Lina Iyer

On Wed, May 09 2018 at 11:49 -0600, Steven Rostedt wrote:

On Wed,  9 May 2018 11:01:52 -0600
Lina Iyer <il...@codeaurora.org> wrote:


Log sent RPMH requests and interrupt responses in FTRACE.


Has this changed since the last time I reviewed it? If not, please add
the: Reviewed-by: Steven Rostedt (VMware) <rost...@goodmis.org>
to you patch queue.


Sorry, no it did not change in v8.
I will add your reviewed-by tag. Thanks Steve.

-- Lina


-- Steve



Cc: Steven Rostedt <rost...@goodmis.org>
Signed-off-by: Lina Iyer <il...@codeaurora.org>
---

Changes in v7:
- varible name changes and white space

Changes in v6:
- struct tcs_response was removed. Fix in trace as well.
Changes in v4:
- fix compilation issues, use __assign_str
- use %#x instead of 0x%08x
Changes in v3:
- Use __string() instead of char *
- fix TRACE_INCLUDE_PATH
---


Re: [PATCH v8 0/2] drivers/qcom: add Command DB support

2018-05-10 Thread Lina Iyer

On Wed, May 09 2018 at 15:30 -0600, Doug Anderson wrote:

Lina

On Wed, May 9, 2018 at 9:42 AM, Lina Iyer <il...@codeaurora.org> wrote:

Hi Andy, David,

These patches have been reviewed by our peers and have recieved no
further comments in the past few weeks. Would you consider merging this
in your trees?


When I look at:

https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git/log/?h=for-next

I see both of your patches (plus Stephen Boyd's patch about making
things endian-agnostic).  ...so I think we're good.  :-)


Excellent. Thank you.

-- Lina



Re: [PATCH v7 04/10] drivers: qcom: rpmh: add RPMH helper functions

2018-05-11 Thread Lina Iyer

Hi Doug,

On Thu, May 10 2018 at 16:37 -0600, Doug Anderson wrote:

Hi,

On Tue, May 8, 2018 at 9:05 AM,  <il...@codeaurora.org> wrote:

On 2018-05-03 14:26, Doug Anderson wrote:
Hi Doug,



Hi,

On Wed, May 2, 2018 at 12:37 PM, Lina Iyer <il...@codeaurora.org> wrote:


+static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_CTRLR];
+static DEFINE_SPINLOCK(rpmh_rsc_lock);
+
+static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
+{
+   int i;
+   struct rsc_drv *p, *drv = dev_get_drvdata(dev->parent);
+   struct rpmh_ctrlr *ctrlr = ERR_PTR(-EINVAL);
+   unsigned long flags;
+
+   if (!drv)
+   return ctrlr;
+
+   for (i = 0; i < RPMH_MAX_CTRLR; i++) {
+   if (rpmh_rsc[i].drv == drv) {
+   ctrlr = _rsc[i];
+   return ctrlr;
+   }
+   }
+
+   spin_lock_irqsave(_rsc_lock, flags);
+   list_for_each_entry(p, _drv_list, list) {
+   if (drv == p) {
+   for (i = 0; i < RPMH_MAX_CTRLR; i++) {
+   if (!rpmh_rsc[i].drv)
+   break;
+   }
+   if (i == RPMH_MAX_CTRLR) {
+   ctrlr = ERR_PTR(-ENOMEM);
+   break;
+   }
+   rpmh_rsc[i].drv = drv;
+   ctrlr = _rsc[i];
+   break;
+   }
+   }
+   spin_unlock_irqrestore(_rsc_lock, flags);



I may have missed something, but to me it appears that this whole
"rsc_drv_list" is pretty pointless.  I wrote up a patch atop your
series to remove it at

<https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1042883/>
and it simplifies the code a whole bunch.  From that patch, my
justification was:


The global rsc_drv_list was (as far as I can tell) racy and not useful
for anything.

I say it is racy because in general you need some sort of mutual
exclusion for lists.  If someone is adding to a list while someone
else is iterating over it then you get badness.

I say it is not useful because the only user of it was
get_rpmh_ctrlr() and the only thing it did was to verify that the
"struct rsc_drv *" that it alrady had was in the list.  How could it
not be?



Note that in v7 of your series you added a spinlock around your access
of "rsc_drv_list", but this doesn't actually remove the race.
Specifically I'm pretty sure that the list primitives don't support
calling list_add() while someone might be iterating over the list and
your spinlock isn't grabbed in rpmh_rsc_probe().

Note that I also say in my patch:


NOTE: After this patch get_rpmh_ctrlr() still seems a bit fishy.  I'm
not sure why every caller would need its own private global cache of
stuff.  ...but I left that part alone.




I am not sure I understand this.


As I've said I haven't reviewed RPMh in any amount of detail and so
perhaps I don't understand something.

OK, I dug a little more and coded up something for you.  Basically
you're doing a whole bunch of iteration / extra work here to try to
come up with a way to associate an extra bit of data with each "struct
rsc_drv".  Rather than that, just add an extra field into "struct
rsc_drv".  Problem solved.

See http://crosreview.com/1054646 for what I mean.


I tried to avoid such pointer references and keep it object oriented
with this approach. I agree that we run through a list of 2 (at the max)
RSC to get the drv* from the rpmh_ctrlr. It is not going to be
expensive.

Another things this helps with is that, if the driver is not a child of
the RSC nodes in DT, then the drvdata of the parent would not a RSC node
and accessing that would result in a crash. This offers a cleaner exit
path for the error case.




I'll try to dig into this more so I could just be confused, but in
general it seems really odd to have a spinlock and something called a
"cache" at this level.  If we need some sort of mutual exclusion or
caching it seems like it should be stored in memory directly
associated with the RPMh device, not some external global.


The idea behind the locking is not to avoid the race between rpmh.c and
rpmh-rsc.c. From the DT, the devices that are dependent on the RSCs are
probed following the probe of the controller. And init is not that we are
worried about.
The condition here is to prevent the rpmh_rsc[] from being modified
concurrently by drivers.


OK, I see the point of the locking now, but not the list still.
Sounds like Matthias agrees with me that the list isn't useful.  Seems
like you should squash my patch at http://crosreview.com/1042883 into
yours.


I saw your approach. I am okay with it for your tree, my approach comes
out of experiences in qcom platforms and how things tend to shape up in
the future. I would want you to consider my reasoning as well, before we
go forward.

Thanks,
Lina



  1   2   3   4   5   6   7   8   9   10   >