3434#include <linux/pm_runtime.h>
3535#include <linux/perf_event.h>
3636#include <asm/sections.h>
37+ #include <asm/local.h>
3738
3839#include "coresight-etm4x.h"
3940
@@ -76,7 +77,7 @@ static int etm4_trace_id(struct coresight_device *csdev)
7677 unsigned long flags ;
7778 int trace_id = -1 ;
7879
79- if (!drvdata -> enable )
80+ if (!local_read ( & drvdata -> mode ) )
8081 return drvdata -> trcid ;
8182
8283 spin_lock_irqsave (& drvdata -> spinlock , flags );
@@ -188,8 +189,7 @@ static void etm4_enable_hw(void *info)
188189 dev_dbg (drvdata -> dev , "cpu: %d enable smp call done\n" , drvdata -> cpu );
189190}
190191
191- static int etm4_enable (struct coresight_device * csdev ,
192- struct perf_event_attr * attr , u32 mode )
192+ static int etm4_enable_sysfs (struct coresight_device * csdev )
193193{
194194 struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
195195 int ret ;
@@ -204,18 +204,46 @@ static int etm4_enable(struct coresight_device *csdev,
204204 etm4_enable_hw , drvdata , 1 );
205205 if (ret )
206206 goto err ;
207- drvdata -> enable = true;
208- drvdata -> sticky_enable = true;
209207
208+ drvdata -> sticky_enable = true;
210209 spin_unlock (& drvdata -> spinlock );
211210
212211 dev_info (drvdata -> dev , "ETM tracing enabled\n" );
213212 return 0 ;
213+
214214err :
215215 spin_unlock (& drvdata -> spinlock );
216216 return ret ;
217217}
218218
219+ static int etm4_enable (struct coresight_device * csdev ,
220+ struct perf_event_attr * attr , u32 mode )
221+ {
222+ int ret ;
223+ u32 val ;
224+ struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
225+
226+ val = local_cmpxchg (& drvdata -> mode , CS_MODE_DISABLED , mode );
227+
228+ /* Someone is already using the tracer */
229+ if (val )
230+ return - EBUSY ;
231+
232+ switch (mode ) {
233+ case CS_MODE_SYSFS :
234+ ret = etm4_enable_sysfs (csdev );
235+ break ;
236+ default :
237+ ret = - EINVAL ;
238+ }
239+
240+ /* The tracer didn't start */
241+ if (ret )
242+ local_set (& drvdata -> mode , CS_MODE_DISABLED );
243+
244+ return ret ;
245+ }
246+
219247static void etm4_disable_hw (void * info )
220248{
221249 u32 control ;
@@ -238,7 +266,7 @@ static void etm4_disable_hw(void *info)
238266 dev_dbg (drvdata -> dev , "cpu: %d disable smp call done\n" , drvdata -> cpu );
239267}
240268
241- static void etm4_disable (struct coresight_device * csdev )
269+ static void etm4_disable_sysfs (struct coresight_device * csdev )
242270{
243271 struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
244272
@@ -256,14 +284,37 @@ static void etm4_disable(struct coresight_device *csdev)
256284 * ensures that register writes occur when cpu is powered.
257285 */
258286 smp_call_function_single (drvdata -> cpu , etm4_disable_hw , drvdata , 1 );
259- drvdata -> enable = false;
260287
261288 spin_unlock (& drvdata -> spinlock );
262289 put_online_cpus ();
263290
264291 dev_info (drvdata -> dev , "ETM tracing disabled\n" );
265292}
266293
294+ static void etm4_disable (struct coresight_device * csdev )
295+ {
296+ u32 mode ;
297+ struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
298+
299+ /*
300+ * For as long as the tracer isn't disabled another entity can't
301+ * change its status. As such we can read the status here without
302+ * fearing it will change under us.
303+ */
304+ mode = local_read (& drvdata -> mode );
305+
306+ switch (mode ) {
307+ case CS_MODE_DISABLED :
308+ break ;
309+ case CS_MODE_SYSFS :
310+ etm4_disable_sysfs (csdev );
311+ break ;
312+ }
313+
314+ if (mode )
315+ local_set (& drvdata -> mode , CS_MODE_DISABLED );
316+ }
317+
267318static const struct coresight_ops_source etm4_source_ops = {
268319 .cpu_id = etm4_cpu_id ,
269320 .trace_id = etm4_trace_id ,
@@ -531,7 +582,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
531582 etmdrvdata [cpu ]-> os_unlock = true;
532583 }
533584
534- if (etmdrvdata [cpu ]-> enable )
585+ if (local_read ( & etmdrvdata [cpu ]-> mode ) )
535586 etm4_enable_hw (etmdrvdata [cpu ]);
536587 spin_unlock (& etmdrvdata [cpu ]-> spinlock );
537588 break ;
@@ -544,7 +595,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
544595
545596 case CPU_DYING :
546597 spin_lock (& etmdrvdata [cpu ]-> spinlock );
547- if (etmdrvdata [cpu ]-> enable )
598+ if (local_read ( & etmdrvdata [cpu ]-> mode ) )
548599 etm4_disable_hw (etmdrvdata [cpu ]);
549600 spin_unlock (& etmdrvdata [cpu ]-> spinlock );
550601 break ;
0 commit comments