* buffer to the perf ring buffer.
  */
 static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf,
+                                    unsigned long src_offset,
                                     unsigned long to_copy)
 {
        long bytes;
-       long pg_idx, pg_offset, src_offset;
+       long pg_idx, pg_offset;
        unsigned long head = etr_perf->head;
        char **dst_pages, *src_buf;
        struct etr_buf *etr_buf = etr_perf->etr_buf;
        pg_idx = head >> PAGE_SHIFT;
        pg_offset = head & (PAGE_SIZE - 1);
        dst_pages = (char **)etr_perf->pages;
-       src_offset = etr_buf->offset + etr_buf->len - to_copy;
 
        while (to_copy > 0) {
                /*
                      void *config)
 {
        bool lost = false;
-       unsigned long flags, size = 0;
+       unsigned long flags, offset, size = 0;
        struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        struct etr_perf_buffer *etr_perf = config;
        struct etr_buf *etr_buf = etr_perf->etr_buf;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        lost = etr_buf->full;
+       offset = etr_buf->offset;
        size = etr_buf->len;
+
+       /*
+        * The ETR buffer may be bigger than the space available in the
+        * perf ring buffer (handle->size).  If so advance the offset so that we
+        * get the latest trace data.  In snapshot mode none of that matters
+        * since we are expected to clobber stale data in favour of the latest
+        * traces.
+        */
        if (!etr_perf->snapshot && size > handle->size) {
-               size = handle->size;
+               u32 mask = tmc_get_memwidth_mask(drvdata);
+
+               /*
+                * Make sure the new size is aligned in accordance with the
+                * requirement explained in function tmc_get_memwidth_mask().
+                */
+               size = handle->size & mask;
+               offset = etr_buf->offset + etr_buf->len - size;
+
+               if (offset >= etr_buf->size)
+                       offset -= etr_buf->size;
                lost = true;
        }
 
        /* Insert barrier packets at the beginning, if there was an overflow */
        if (lost)
                tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
-       tmc_etr_sync_perf_buffer(etr_perf, size);
+       tmc_etr_sync_perf_buffer(etr_perf, offset, size);
 
        /*
         * In snapshot mode we simply increment the head by the number of byte