On Thu, Feb 25, 2021 at 07:35:42PM +0000, Suzuki K Poulose wrote: > From: Anshuman Khandual <anshuman.khand...@arm.com> > > Trace Buffer Extension (TRBE) implements a trace buffer per CPU which is > accessible via the system registers. The TRBE supports different addressing > modes including CPU virtual address and buffer modes including the circular > buffer mode. The TRBE buffer is addressed by a base pointer (TRBBASER_EL1), > an write pointer (TRBPTR_EL1) and a limit pointer (TRBLIMITR_EL1). But the > access to the trace buffer could be prohibited by a higher exception level > (EL3 or EL2), indicated by TRBIDR_EL1.P. The TRBE can also generate a CPU > private interrupt (PPI) on address translation errors and when the buffer > is full. Overall implementation here is inspired from the Arm SPE driver. > > Cc: Mathieu Poirier <mathieu.poir...@linaro.org> > Cc: Mike Leach <mike.le...@linaro.org> > Cc: Suzuki K Poulose <suzuki.poul...@arm.com> > Signed-off-by: Anshuman Khandual <anshuman.khand...@arm.com> > Signed-off-by: Suzuki K Poulose <suzuki.poul...@arm.com> > --- > Changes: > - Replaced TRBLIMITR_LIMIT_SHIFT with TRBBASER_BASE_SHIFT in > set_trbe_base_pointer() > - Dropped TRBBASER_BASE_MASK and TRBBASER_BASE_SHIFT from > get_trbe_base_pointer() > - Indentation changes for TRBE_BSC_NOT_[STOPPED|FILLED|TRIGGERED] definitions > - Moved DECLARE_PER_CPU(...., csdev_sink) into coresight-priv.h > - Moved isb() from trbe_enable_hw() into set_trbe_limit_pointer_enabled() > - Dropped the space after type casting before vmap() > - Return 0 instead of EINVAL in arm_trbe_update_buffer() > - Add a comment in trbe_handle_overflow() > - Add a comment in arm_trbe_cpu_startup() > - Unregister coresight TRBE device when not supported > - Fix potential NULL handle dereference in IRQ handler with a spurious IRQ > - Read TRBIDR after is_trbe_programmable() in arm_trbe_probe_coresight_cpu() > - Replaced and modified trbe_drain_and_disable_local() in IRQ handler > - Updated arm_trbe_update_buffer() for handling a missing interrupt > - Dropped kfree() for all devm_xxx() allocated buffer > - Dropped additional blank line in documentation coresight/coresight-trbe.rst > - Added Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe > - Changed CONFIG_CORESIGHT_TRBE options, dependencies and helper write up > - Added comment for irq_work_run() > - Updated comment for minumum buffer length in arm_trbe_alloc_buffer() > - Dropped redundant smp_processor_id() from arm_trbe_probe_coresight_cpu() > - Fixed indentation in arm_trbe_probe_cpuhp() > - Added static for arm_trbe_free_buffer() > - Added comment for trbe_base element in trbe_buf structure > - Dropped IS_ERR() check from vmap() returned pointer > - Added WARN_ON(trbe_csdev) in arm_trbe_probe_coresight_cpu() > - Changed TRBE device names from arm_trbeX to just trbeX > - Dropped unused argument perf_output_handle from trbe_get_fault_act() > - Dropped IS_ERR() from kzalloc_node()/kcalloc() buffer in > arm_trbe_alloc_buffer() > - Dropped IS_ERR() and return -ENOMEM in arm_trbe_probe_coresight() > - Moved TRBE HW disabling before coresight cleanup in > arm_trbe_remove_coresight_cpu() > - Changed error return codes from arm_trbe_probe_irq() > - Changed error return codes from arm_trbe_device_probe() > - Changed arm_trbe_remove_coresight() order in arm_trbe_device_remove() > - Changed TRBE CPU support probe/remove sequence with for_each_cpu() iterator > - Changed coresight_register() in arm_trbe_probe_coresight_cpu() > - Changed error return code when cpuhp_setup_state_multi() fails in > arm_trbe_probe_cpuhp() > - Changed error return code when cpuhp_state_add_instance() fails in > arm_trbe_probe_cpuhp() > - Changed trbe_dbm as trbe_flag including its sysfs interface > - Handle race between update_buffer & IRQ handler > - Rework and split the TRBE probe to avoid lockdep due to memory allocation > from IPI calls (via coresight_register()) > - Fix handle->head updat for snapshot mode.
All of the above make this driver much easier to read. > --- > .../testing/sysfs-bus-coresight-devices-trbe | 14 + > .../trace/coresight/coresight-trbe.rst | 38 + > drivers/hwtracing/coresight/Kconfig | 14 + > drivers/hwtracing/coresight/Makefile | 1 + > drivers/hwtracing/coresight/coresight-trbe.c | 1149 +++++++++++++++++ > drivers/hwtracing/coresight/coresight-trbe.h | 153 +++ > 6 files changed, 1369 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe > create mode 100644 Documentation/trace/coresight/coresight-trbe.rst > create mode 100644 drivers/hwtracing/coresight/coresight-trbe.c > create mode 100644 drivers/hwtracing/coresight/coresight-trbe.h > [...] > + > +static void *arm_trbe_alloc_buffer(struct coresight_device *csdev, > + struct perf_event *event, void **pages, > + int nr_pages, bool snapshot) > +{ > + struct trbe_buf *buf; > + struct page **pglist; > + int i; > + > + /* > + * TRBE LIMIT and TRBE WRITE pointers must be page aligned. But with > + * just a single page, there would not be any room left while writing > + * into a partially filled TRBE buffer after the page size alignment. > + * Hence restrict the minimum buffer size as two pages. > + */ > + if (nr_pages < 2) > + return NULL; > + > + buf = kzalloc_node(sizeof(*buf), GFP_KERNEL, trbe_alloc_node(event)); > + if (!buf) > + return ERR_PTR(-ENOMEM); > + > + pglist = kcalloc(nr_pages, sizeof(*pglist), GFP_KERNEL); > + if (!pglist) { > + kfree(buf); > + return ERR_PTR(-ENOMEM); > + } > + > + for (i = 0; i < nr_pages; i++) > + pglist[i] = virt_to_page(pages[i]); > + > + buf->trbe_base = (unsigned long)vmap(pglist, nr_pages, VM_MAP, > PAGE_KERNEL); > + if (!buf->trbe_base) { > + kfree(pglist); > + kfree(buf); > + return ERR_PTR(buf->trbe_base); return ERR_PTR(-ENOMEM); > + } > + buf->trbe_limit = buf->trbe_base + nr_pages * PAGE_SIZE; > + buf->trbe_write = buf->trbe_base; > + buf->snapshot = snapshot; > + buf->nr_pages = nr_pages; > + buf->pages = pages; > + kfree(pglist); > + return buf; > +} > +