Merge tag 'module_init-alternate_initcall-v4.1-rc8' of git://git.kernel.org/pub/scm...
[firefly-linux-kernel-4.4.55.git] / arch / x86 / kernel / cpu / perf_event_intel_pt.c
index 0d52d76f1397c7cc00433bb3607bbb8badf3f3bc..183de719628d2a4740d20a173a6c950f35c322fa 100644 (file)
@@ -187,15 +187,6 @@ static bool pt_event_valid(struct perf_event *event)
  * These all are cpu affine and operate on a local PT
  */
 
-static bool pt_is_running(void)
-{
-       u64 ctl;
-
-       rdmsrl(MSR_IA32_RTIT_CTL, ctl);
-
-       return !!(ctl & RTIT_CTL_TRACEEN);
-}
-
 static void pt_config(struct perf_event *event)
 {
        u64 reg;
@@ -609,7 +600,12 @@ static unsigned int pt_topa_next_entry(struct pt_buffer *buf, unsigned int pg)
  * @handle:    Current output handle.
  *
  * Place INT and STOP marks to prevent overwriting old data that the consumer
- * hasn't yet collected.
+ * hasn't yet collected and waking up the consumer after a certain fraction of
+ * the buffer has filled up. Only needed and sensible for non-snapshot counters.
+ *
+ * This obviously relies on buf::head to figure out buffer markers, so it has
+ * to be called after pt_buffer_reset_offsets() and before the hardware tracing
+ * is enabled.
  */
 static int pt_buffer_reset_markers(struct pt_buffer *buf,
                                   struct perf_output_handle *handle)
@@ -618,9 +614,6 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
        unsigned long head = local64_read(&buf->head);
        unsigned long idx, npages, wakeup;
 
-       if (buf->snapshot)
-               return 0;
-
        /* can't stop in the middle of an output region */
        if (buf->output_off + handle->size + 1 <
            sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size))
@@ -674,7 +667,7 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
        struct topa *cur = buf->first, *prev = buf->last;
        struct topa_entry *te_cur = TOPA_ENTRY(cur, 0),
                *te_prev = TOPA_ENTRY(prev, prev->last - 1);
-       int pg = 0, idx = 0, ntopa = 0;
+       int pg = 0, idx = 0;
 
        while (pg < buf->nr_pages) {
                int tidx;
@@ -689,9 +682,9 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
                        /* advance to next topa table */
                        idx = 0;
                        cur = list_entry(cur->list.next, struct topa, list);
-                       ntopa++;
-               } else
+               } else {
                        idx++;
+               }
                te_cur = TOPA_ENTRY(cur, idx);
        }
 
@@ -703,7 +696,14 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
  * @head:      Write pointer (aux_head) from AUX buffer.
  *
  * Find the ToPA table and entry corresponding to given @head and set buffer's
- * "current" pointers accordingly.
+ * "current" pointers accordingly. This is done after we have obtained the
+ * current aux_head position from a successful call to perf_aux_output_begin()
+ * to make sure the hardware is writing to the right place.
+ *
+ * This function modifies buf::{cur,cur_idx,output_off} that will be programmed
+ * into PT msrs when the tracing is enabled and buf::head and buf::data_size,
+ * which are used to determine INT and STOP markers' locations by a subsequent
+ * call to pt_buffer_reset_markers().
  */
 static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
 {
@@ -901,6 +901,7 @@ void intel_pt_interrupt(void)
                }
 
                pt_buffer_reset_offsets(buf, pt->handle.head);
+               /* snapshot counters don't use PMI, so it's safe */
                ret = pt_buffer_reset_markers(buf, &pt->handle);
                if (ret) {
                        perf_aux_output_end(&pt->handle, 0, true);
@@ -923,7 +924,7 @@ static void pt_event_start(struct perf_event *event, int mode)
        struct pt *pt = this_cpu_ptr(&pt_ctx);
        struct pt_buffer *buf = perf_get_aux(&pt->handle);
 
-       if (pt_is_running() || !buf || pt_buffer_is_full(buf, pt)) {
+       if (!buf || pt_buffer_is_full(buf, pt)) {
                event->hw.state = PERF_HES_STOPPED;
                return;
        }
@@ -954,7 +955,6 @@ static void pt_event_stop(struct perf_event *event, int mode)
        event->hw.state = PERF_HES_STOPPED;
 
        if (mode & PERF_EF_UPDATE) {
-               struct pt *pt = this_cpu_ptr(&pt_ctx);
                struct pt_buffer *buf = perf_get_aux(&pt->handle);
 
                if (!buf)