Commit f188b5e7 authored by Andrew Murray's avatar Andrew Murray Committed by Greg Kroah-Hartman

coresight: etm4x: Save/restore state across CPU low power states

Some hardware will ignore bit TRCPDCR.PU which is used to signal
to hardware that power should not be removed from the trace unit.
Let's mitigate against this by conditionally saving and restoring
the trace unit state when the CPU enters low power states.

This patchset introduces a firmware property named
'arm,coresight-loses-context-with-cpu' - when this is present the
hardware state will be conditionally saved and restored.

A module parameter 'pm_save_enable' is also introduced which can
be configured to override the firmware property. This can be set
to never allow save/restore or to conditionally allow it (only for
self-hosted). The default value is determined by firmware.

We avoid saving the hardware state when self-hosted coresight isn't
in use to reduce PM latency - we can't determine this by reading the
claim tags (TRCCLAIMCLR) as these are 'trace' registers which need
power and clocking, something we can't easily provide in the PM
context. Therefore we rely on the existing drvdata->mode internal
state that is set when self-hosted coresight is used (and powered).
Signed-off-by: default avatarAndrew Murray <andrew.murray@arm.com>
Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20191104181251.26732-2-mathieu.poirier@linaro.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 891e6036
...@@ -175,6 +175,7 @@ ...@@ -175,6 +175,7 @@
ETM_MODE_EXCL_USER) ETM_MODE_EXCL_USER)
#define TRCSTATR_IDLE_BIT 0 #define TRCSTATR_IDLE_BIT 0
#define TRCSTATR_PMSTABLE_BIT 1
#define ETM_DEFAULT_ADDR_COMP 0 #define ETM_DEFAULT_ADDR_COMP 0
/* PowerDown Control Register bits */ /* PowerDown Control Register bits */
...@@ -281,6 +282,65 @@ struct etmv4_config { ...@@ -281,6 +282,65 @@ struct etmv4_config {
u32 ext_inp; u32 ext_inp;
}; };
/**
* struct etm4_save_state - state to be preserved when ETM is without power
*/
struct etmv4_save_state {
u32 trcprgctlr;
u32 trcprocselr;
u32 trcconfigr;
u32 trcauxctlr;
u32 trceventctl0r;
u32 trceventctl1r;
u32 trcstallctlr;
u32 trctsctlr;
u32 trcsyncpr;
u32 trcccctlr;
u32 trcbbctlr;
u32 trctraceidr;
u32 trcqctlr;
u32 trcvictlr;
u32 trcviiectlr;
u32 trcvissctlr;
u32 trcvipcssctlr;
u32 trcvdctlr;
u32 trcvdsacctlr;
u32 trcvdarcctlr;
u32 trcseqevr[ETM_MAX_SEQ_STATES];
u32 trcseqrstevr;
u32 trcseqstr;
u32 trcextinselr;
u32 trccntrldvr[ETMv4_MAX_CNTR];
u32 trccntctlr[ETMv4_MAX_CNTR];
u32 trccntvr[ETMv4_MAX_CNTR];
u32 trcrsctlr[ETM_MAX_RES_SEL * 2];
u32 trcssccr[ETM_MAX_SS_CMP];
u32 trcsscsr[ETM_MAX_SS_CMP];
u32 trcsspcicr[ETM_MAX_SS_CMP];
u64 trcacvr[ETM_MAX_SINGLE_ADDR_CMP];
u64 trcacatr[ETM_MAX_SINGLE_ADDR_CMP];
u64 trccidcvr[ETMv4_MAX_CTXID_CMP];
u32 trcvmidcvr[ETM_MAX_VMID_CMP];
u32 trccidcctlr0;
u32 trccidcctlr1;
u32 trcvmidcctlr0;
u32 trcvmidcctlr1;
u32 trcclaimset;
u32 cntr_val[ETMv4_MAX_CNTR];
u32 seq_state;
u32 vinst_ctrl;
u32 ss_status[ETM_MAX_SS_CMP];
u32 trcpdcr;
};
/** /**
* struct etm4_drvdata - specifics associated to an ETM component * struct etm4_drvdata - specifics associated to an ETM component
* @base: Memory mapped base address for this component. * @base: Memory mapped base address for this component.
...@@ -336,6 +396,8 @@ struct etmv4_config { ...@@ -336,6 +396,8 @@ struct etmv4_config {
* @atbtrig: If the implementation can support ATB triggers * @atbtrig: If the implementation can support ATB triggers
* @lpoverride: If the implementation can support low-power state over. * @lpoverride: If the implementation can support low-power state over.
* @config: structure holding configuration parameters. * @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
* @state_needs_restore: True when there is context to restore after PM exit
*/ */
struct etmv4_drvdata { struct etmv4_drvdata {
void __iomem *base; void __iomem *base;
...@@ -381,6 +443,8 @@ struct etmv4_drvdata { ...@@ -381,6 +443,8 @@ struct etmv4_drvdata {
bool atbtrig; bool atbtrig;
bool lpoverride; bool lpoverride;
struct etmv4_config config; struct etmv4_config config;
struct etmv4_save_state *save_state;
bool state_needs_restore;
}; };
/* Address comparator access types */ /* Address comparator access types */
......
...@@ -1308,6 +1308,12 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict, ...@@ -1308,6 +1308,12 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
return -ENOENT; return -ENOENT;
} }
bool coresight_loses_context_with_cpu(struct device *dev)
{
return fwnode_property_present(dev_fwnode(dev),
"arm,coresight-loses-context-with-cpu");
}
/* /*
* coresight_alloc_device_name - Get an index for a given device in the * coresight_alloc_device_name - Get an index for a given device in the
* device index list specific to a driver. An index is allocated for a * device index list specific to a driver. An index is allocated for a
......
...@@ -285,6 +285,8 @@ extern void coresight_disclaim_device(void __iomem *base); ...@@ -285,6 +285,8 @@ extern void coresight_disclaim_device(void __iomem *base);
extern void coresight_disclaim_device_unlocked(void __iomem *base); extern void coresight_disclaim_device_unlocked(void __iomem *base);
extern char *coresight_alloc_device_name(struct coresight_dev_list *devs, extern char *coresight_alloc_device_name(struct coresight_dev_list *devs,
struct device *dev); struct device *dev);
extern bool coresight_loses_context_with_cpu(struct device *dev);
#else #else
static inline struct coresight_device * static inline struct coresight_device *
coresight_register(struct coresight_desc *desc) { return NULL; } coresight_register(struct coresight_desc *desc) { return NULL; }
...@@ -307,6 +309,10 @@ static inline int coresight_claim_device(void __iomem *base) ...@@ -307,6 +309,10 @@ static inline int coresight_claim_device(void __iomem *base)
static inline void coresight_disclaim_device(void __iomem *base) {} static inline void coresight_disclaim_device(void __iomem *base) {}
static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} static inline void coresight_disclaim_device_unlocked(void __iomem *base) {}
static inline bool coresight_loses_context_with_cpu(struct device *dev)
{
return false;
}
#endif #endif
extern int coresight_get_cpu(struct device *dev); extern int coresight_get_cpu(struct device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment