Yes Working on getting comments updated for other patches as well before I resubmit
-----Original Message----- From: Bruce Ashfield [mailto:bruce.ashfi...@windriver.com] Sent: Monday, March 24, 2014 6:09 AM To: Svennebring, Jonas; Charlie Paul; linux-yocto@yoctoproject.org Cc: Paul, Charlie Subject: Re: [PATCH 47/57] Basic perf support for axxia plaform block provided by LSI. On 14-03-24 07:24 AM, Svennebring, Jonas wrote: > Hi, > > The basic support includes: > * Generic AXXIA SMON (Statistic Monitor) functionality. > > * Support for Memory Controllers: > - DDRC, DDR Controllers. > - ELM, Encryption Memory Controllers . > > *Preparation for support of: > - PCX, integrated Ethernet switch. > - VP, virtual pipeline packet processing engines. > > Documentation, VP/PCX support as well as patch alignment with coming ARM L3$ > and interconnect is in the workings. > Looks good. Thanks for the summary. Charlie: can we capture this in the log ? Bruce > Best Regards, > > //Jonas > > -----Original Message----- > From: Bruce Ashfield [mailto:bruce.ashfi...@windriver.com] > Sent: den 20 mars 2014 09:44 > To: Charlie Paul; linux-yocto@yoctoproject.org > Cc: charlie.p...@windriver.com; Svennebring, Jonas > Subject: Re: [PATCH 47/57] Basic perf support for axxia plaform block > provided by LSI. > > Can we get a short feature listing of what is included in the basic support ? > > A summary here is fine, and perhaps a README or other perf documentation > update as well. > > Bruce > > On 14-03-18 12:56 AM, Charlie Paul wrote: >> From: Jonas Svennebring <jonas.svennebr...@lsi.com> >> >> Signed-off-by: Jonas Svennebring <jonas.svennebr...@lsi.com> >> --- >> arch/arm/mach-axxia/perf_event_memc.c | 130 ++++++++++++++ >> arch/arm/mach-axxia/perf_event_memc.h | 62 +++++++ >> arch/arm/mach-axxia/perf_event_pcx.c | 46 +++++ >> arch/arm/mach-axxia/perf_event_platform.c | 270 >> +++++++++++++++++++++++++++++ >> arch/arm/mach-axxia/perf_event_platform.h | 10 ++ >> arch/arm/mach-axxia/perf_event_vp.c | 51 ++++++ >> arch/arm/mach-axxia/smon.c | 200 +++++++++++++++++++++ >> arch/arm/mach-axxia/smon.h | 71 ++++++++ >> 8 files changed, 840 insertions(+) >> create mode 100644 arch/arm/mach-axxia/perf_event_memc.c >> create mode 100644 arch/arm/mach-axxia/perf_event_memc.h >> create mode 100644 arch/arm/mach-axxia/perf_event_pcx.c >> create mode 100644 arch/arm/mach-axxia/perf_event_platform.c >> create mode 100644 arch/arm/mach-axxia/perf_event_platform.h >> create mode 100644 arch/arm/mach-axxia/perf_event_vp.c >> create mode 100644 arch/arm/mach-axxia/smon.c >> create mode 100644 arch/arm/mach-axxia/smon.h >> >> diff --git a/arch/arm/mach-axxia/perf_event_memc.c >> b/arch/arm/mach-axxia/perf_event_memc.c >> new file mode 100644 >> index 0000000..a20fc8a >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_memc.c >> @@ -0,0 +1,130 @@ >> +/* >> + * arch/arm/mach-axxia/perf_event_memc.c >> + * included from arch/arm/mach-axxia/perf_event_platform.c >> + * >> + * Support for the LSI Axxia boards based on ARM cores. >> + * >> + * Copyright (C) 2014 LSI >> + * >> + * This program is free software; you can redistribute it and/or >> +modify >> + * it under the terms of the GNU General Public License as published >> +by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> +02111-1307 USA */ >> + >> +#include "perf_event_memc.h" >> + >> +static void memc_startup_init(void) >> +{ >> + smon_init_ncp(&ddrc0_smon, DDRC0, DDRC_PERF, DDRC_SMON); >> + smon_init_ncp(&ddrc1_smon, DDRC1, DDRC_PERF, DDRC_SMON); >> + smon_init_mem(&elm0_smon, ELM0, ELM_SMON); >> + smon_init_mem(&elm1_smon, ELM1, ELM_SMON); } >> + >> +static uint32_t memc_pmu_event_init(uint32_t event, struct >> +perf_event >> +*pevent) { >> + return 0; >> +} >> + >> +static void memc_pmu_event_destroy(uint32_t event, struct perf_event >> +*pevent) { >> + smon_stop_if_unassigned(&ddrc0_smon); >> + smon_stop_if_unassigned(&ddrc1_smon); >> + smon_stop_if_unassigned(&elm0_smon); >> + smon_stop_if_unassigned(&elm1_smon); >> +} >> + >> +static uint32_t memc_pmu_event_add(uint32_t ev, struct perf_event >> +*pevent) { >> + uint32_t ret; >> + >> + if (ev >= DDRC0_OFFSET && ev <= DDRC0_SMON_MAX) { >> + >> + ret = smon_allocate(&ddrc0_smon, ev - DDRC0_OFFSET); >> + if (ret != 0) >> + return ret; >> + >> + ret = smon_start(&ddrc0_smon, ev - DDRC0_OFFSET); >> + if (ret != 0) >> + return ret; >> + } else if (ev >= DDRC1_OFFSET && ev <= DDRC1_SMON_MAX) { >> + >> + ret = smon_allocate(&ddrc1_smon, ev - DDRC1_OFFSET); >> + if (ret != 0) >> + return ret; >> + >> + ret = smon_start(&ddrc1_smon, ev - DDRC1_OFFSET); >> + if (ret != 0) >> + return ret; >> + } else if (ev >= ELM0_OFFSET && ev <= ELM0_SMON_MAX) { >> + >> + ret = smon_allocate(&elm0_smon, ev - ELM0_OFFSET); >> + if (ret != 0) >> + return ret; >> + >> + ret = smon_start(&elm0_smon, ev - ELM0_OFFSET); >> + if (ret != 0) >> + return ret; >> + } else if (ev >= ELM1_OFFSET && ev <= ELM1_SMON_MAX) { >> + >> + ret = smon_allocate(&elm1_smon, ev - ELM1_OFFSET); >> + if (ret != 0) >> + return ret; >> + >> + ret = smon_start(&elm1_smon, ev - ELM1_OFFSET); >> + if (ret != 0) >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +/* >> + * Remove event and return counter update. >> + */ >> +static uint32_t memc_pmu_event_del(uint32_t ev, struct perf_event *pevent, >> + int flags) >> +{ >> + uint32_t count = 0; >> + >> + if (ev >= DDRC0_OFFSET && ev <= DDRC0_SMON_MAX) { >> + >> + count = smon_read(&ddrc0_smon, ev - DDRC0_OFFSET); >> + if (count == -ENOEVENT) >> + count = 0; >> + >> + smon_deallocate(&ddrc0_smon, ev - DDRC0_OFFSET); >> + } else if (ev >= DDRC1_OFFSET && ev <= DDRC1_SMON_MAX) { >> + >> + count = smon_read(&ddrc1_smon, ev - DDRC1_OFFSET); >> + if (count == -ENOEVENT) >> + count = 0; >> + >> + smon_deallocate(&ddrc1_smon, ev - DDRC1_OFFSET); >> + } else if (ev >= ELM0_OFFSET && ev <= ELM0_SMON_MAX) { >> + count = smon_read(&elm0_smon, ev - ELM0_OFFSET); >> + if (count == -ENOEVENT) >> + count = 0; >> + >> + smon_deallocate(&elm0_smon, ev - ELM0_OFFSET); >> + } else if (ev >= ELM1_OFFSET && ev <= ELM1_SMON_MAX) { >> + >> + count = smon_read(&elm1_smon, ev - ELM1_OFFSET); >> + if (count == -ENOEVENT) >> + count = 0; >> + >> + smon_deallocate(&elm1_smon, ev - ELM1_OFFSET); >> + } >> + >> + return count; >> +} >> diff --git a/arch/arm/mach-axxia/perf_event_memc.h >> b/arch/arm/mach-axxia/perf_event_memc.h >> new file mode 100644 >> index 0000000..e4a4f7d >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_memc.h >> @@ -0,0 +1,62 @@ >> +/* >> + * arch/arm/mach-axxia/perf_event_memc.h >> + * included from arch/arm/mach-axxia/perf_event_memc.c >> + * >> + * Support for the LSI Axxia boards based on ARM cores. >> + * >> + * Copyright (C) 2014 LSI >> + * >> + * This program is free software; you can redistribute it and/or >> +modify >> + * it under the terms of the GNU General Public License as published >> +by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> +02111-1307 USA */ >> + >> +#ifndef __ASM__ARCH_AXXIA_PERF_EVENT_MEMC_H >> +#define __ASM__ARCH_AXXIA_PERF_EVENT_MEMC_H >> + >> +#define DDRC0_OFFSET 0x00 >> +#define DDRC0_SMON_MAX (DDRC0_OFFSET + 22) #define DDRC1_OFFSET >> +0x100 #define DDRC1_SMON_MAX (DDRC1_OFFSET + 22) >> + >> +#define ELM0_OFFSET 0x200 >> +#define ELM0_SMON_MAX (ELM0_OFFSET + 15) #define ELM1_OFFSET 0x300 >> +#define ELM1_SMON_MAX (ELM1_OFFSET + 15) >> + >> +/* Node */ >> +#define DDRC0 0x0f >> +#define DDRC1 0x22 >> +/* Target */ >> +#define DDRC_PERF 0x02 >> + >> +/* Address */ >> +#ifdef AXM55XX_R1 >> +#define DDRC_SMON 0x40 >> +#endif >> +#ifdef AXM55XX_R2 >> +#define DDRC_SMON 0xA0 >> +#endif >> + >> +/* Base Address */ >> +#define ELM0 0x2010060000 >> +#define ELM1 0x2010070000 >> +/* SMON Offset */ >> +#define ELM_SMON (0x300/4) >> + >> +struct smon_s ddrc0_smon; >> +struct smon_s ddrc1_smon; >> +struct smon_s elm0_smon; >> +struct smon_s elm1_smon; >> + >> +#endif >> diff --git a/arch/arm/mach-axxia/perf_event_pcx.c >> b/arch/arm/mach-axxia/perf_event_pcx.c >> new file mode 100644 >> index 0000000..a419c67 >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_pcx.c >> @@ -0,0 +1,46 @@ >> +/* >> + * arch/arm/mach-axxia/perf_event_pcx.c >> + * included from arch/arm/mach-axxia/perf_event_platform.c >> + * >> + * Support for the LSI Axxia boards based on ARM cores. >> + * >> + * Copyright (C) 2014 LSI >> + * >> + * This program is free software; you can redistribute it and/or >> +modify >> + * it under the terms of the GNU General Public License as published >> +by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> +02111-1307 USA */ >> + >> +/* >> + * Generic PCX >> + */ >> + >> +static void pcx_startup_init(void) >> +{ >> +} >> + >> +static uint32_t pcx_pmu_event_init(uint32_t ev, struct perf_event >> +*event) { >> + return 0; >> +} >> + >> +static uint32_t pcx_pmu_event_add(uint32_t ev, struct perf_event >> +*event) { >> + return 0; >> +} >> + >> +static uint32_t pcx_pmu_event_del(uint32_t ev, struct perf_event *event, >> + int flags) >> +{ >> + return 0; >> +} >> diff --git a/arch/arm/mach-axxia/perf_event_platform.c >> b/arch/arm/mach-axxia/perf_event_platform.c >> new file mode 100644 >> index 0000000..83a221d >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_platform.c >> @@ -0,0 +1,270 @@ >> +/* >> + * arch/arm/mach-axxia/perf_event_platform.c >> + * >> + * Support for the LSI Axxia boards based on ARM cores. >> + * >> + * Copyright (C) 2014 LSI >> + * >> + * This program is free software; you can redistribute it and/or >> +modify >> + * it under the terms of the GNU General Public License as published >> +by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> +02111-1307 USA */ >> + >> +#include <linux/init.h> >> +#include <linux/module.h> >> +#include <linux/kernel.h> >> +#include <linux/platform_device.h> >> + >> +#include <linux/bitmap.h> >> +#include <linux/cpu_pm.h> >> +#include <linux/export.h> >> +#include <linux/of.h> >> +#include <linux/slab.h> >> +#include <linux/spinlock.h> >> + >> +#include <asm/cputype.h> >> +#include <asm/irq_regs.h> >> +#include <asm/pmu.h> >> + >> +#include <linux/kthread.h> >> +#include <linux/sched.h> >> + >> +#include <linux/cpu.h> >> +#include <linux/reboot.h> >> +#include <linux/syscore_ops.h> >> + >> +#include <linux/proc_fs.h> >> + >> +#include <linux/io.h> >> +#include <asm/cacheflush.h> >> +#include <../../../drivers/misc/lsi-ncr.h> >> + >> +#include "perf_event_platform.h" >> + >> +#include "smon.h" >> + >> +/* >> + * Include code for individual block support */ >> + >> +#include "perf_event_pcx.c" >> +#include "perf_event_vp.c" >> +#include "perf_event_memc.c" >> + >> +/* >> + * General platform perf code, muxed out to individual blocks */ >> + >> +int platform_pmu_event_idx(struct perf_event *event) { >> + return 0; >> +} >> + >> +int platform_pmu_event_init(struct perf_event *event) { >> + uint64_t ev = event->attr.config; >> + >> + if (event->attr.type != event->pmu->type) >> + return -ENOENT; >> + >> + if ((ev < AXM_55XX_PLATFORM_BASE) || (ev > AXM_55XX_PLATFORM_MAX)) >> + return -ENOENT; >> + >> + event->hw.config = ev - AXM_55XX_PLATFORM_BASE; >> + >> + event->hw.idx = -1; >> + event->hw.config_base = 1; >> + >> +/* >> + if (event->group_leader != event) { >> + printk("This is not the group leader!\n"); >> + printk("event->group_leader 0x%x\n", (unsigned >> +int)event->group_leader); } */ >> + >> + if (event->attr.exclude_user) >> + return -ENOTSUPP; >> + if (event->attr.exclude_kernel) >> + return -ENOTSUPP; >> + if (event->attr.exclude_idle) >> + return -ENOTSUPP; >> + >> + event->hw.last_period = event->hw.sample_period; >> + local64_set(&event->hw.period_left, event->hw.last_period); >> +/* >> + event->destroy = hw_perf_event_destroy; >> +*/ >> + local64_set(&event->count, 0); >> + >> + if (ev >= AXM_55XX_VP_BASE && ev <= AXM_55XX_VP_MAX) >> + vp_pmu_event_init(ev - AXM_55XX_VP_BASE, event); >> + else if (ev >= AXM_55XX_PCX_BASE && ev <= AXM_55XX_PCX_MAX) >> + pcx_pmu_event_init(ev - AXM_55XX_PCX_BASE, event); >> + else if (ev >= AXM_55XX_MEMC_BASE && ev <= AXM_55XX_MEMC_MAX) >> + memc_pmu_event_init(ev - AXM_55XX_MEMC_BASE, event); >> + else >> + pr_info("Platform perf, undefined event, %llu\n", ev); >> + >> + return 0; >> +} >> + >> +static int platform_pmu_event_add(struct perf_event *event, int >> +flags) { >> + uint64_t ev = event->attr.config; >> + >> + if (ev >= AXM_55XX_VP_BASE && ev <= AXM_55XX_VP_MAX) >> + vp_pmu_event_add(ev - AXM_55XX_VP_BASE, event); >> + else if (ev >= AXM_55XX_PCX_BASE && ev <= AXM_55XX_PCX_MAX) >> + pcx_pmu_event_add(ev - AXM_55XX_PCX_BASE, event); >> + else if (ev >= AXM_55XX_MEMC_BASE && ev <= AXM_55XX_MEMC_MAX) >> + memc_pmu_event_add(ev - AXM_55XX_MEMC_BASE, event); >> + >> + return 0; >> +} >> + >> +static void platform_pmu_event_del(struct perf_event *event, int >> +flags) { >> + uint64_t ev = event->attr.config; >> + uint32_t n; >> + >> + if (ev >= AXM_55XX_VP_BASE && ev <= AXM_55XX_VP_MAX) { >> + n = vp_pmu_event_del(ev - AXM_55XX_VP_BASE, event, flags); >> + local64_add(n, &event->count); >> + } else if (ev >= AXM_55XX_PCX_BASE && ev <= AXM_55XX_PCX_MAX) { >> + n = pcx_pmu_event_del(ev - AXM_55XX_PCX_BASE, event, flags); >> + local64_add(n, &event->count); >> + } else if (ev >= AXM_55XX_MEMC_BASE && ev <= AXM_55XX_MEMC_MAX) { >> + n = memc_pmu_event_del(ev - AXM_55XX_MEMC_BASE, event, flags); >> + local64_add(n, &event->count); >> + } else { >> + local64_set(&event->count, 0); >> + } >> +} >> + >> +static void platform_pmu_event_start(struct perf_event *event, int >> +flags) { } >> + >> +static void platform_pmu_event_stop(struct perf_event *event, int >> +flags) { } >> + >> +static void platform_pmu_event_read(struct perf_event *event) { >> + uint64_t ev = event->attr.config; >> + uint32_t n; >> + >> + if (ev >= AXM_55XX_VP_BASE && ev <= AXM_55XX_VP_MAX) { >> + n = vp_pmu_event_del(ev - AXM_55XX_VP_BASE, event, 0); >> + local64_add(n, &event->count); >> + } else if (ev >= AXM_55XX_PCX_BASE && ev <= AXM_55XX_PCX_MAX) { >> + n = pcx_pmu_event_del(ev - AXM_55XX_PCX_BASE, event, 0); >> + local64_add(n, &event->count); >> + } else if (ev >= AXM_55XX_MEMC_BASE && ev <= AXM_55XX_MEMC_MAX) { >> + n = memc_pmu_event_del(ev - AXM_55XX_MEMC_BASE, event, 0); >> + local64_add(n, &event->count); >> + } >> +} >> + >> +/* >> + * Device >> + */ >> + >> +static void axmperf_device_release(struct device *dev) { >> + pr_warn("AXM55xxPlatformPerf release device\n"); } >> + >> +static struct platform_device axmperf_device = { >> + .name = "AXM55xxPlatformPerf", >> + .id = 0, >> + .dev = { >> + .release = axmperf_device_release, >> + }, >> +}; >> + >> +/* >> + * Driver >> + */ >> + >> +#define PLATFORM_PMU_NAME_LEN 32 >> + >> +struct lsi_platform_pmu { >> + struct pmu pmu; >> + char name[PLATFORM_PMU_NAME_LEN]; >> +}; >> + >> +static int axmperf_probe(struct platform_device *dev) { >> + int ret; >> + struct lsi_platform_pmu *axm_pmu; >> + >> + axm_pmu = kzalloc(sizeof(struct lsi_platform_pmu), GFP_KERNEL); >> + if (!axm_pmu) { >> + pr_warn("Failed platform perf memory alloc!\n"); >> + return -ENOMEM; >> + } >> + >> + axm_pmu->pmu = (struct pmu) { >> + .attr_groups = 0, >> + .event_init = platform_pmu_event_init, >> + .add = platform_pmu_event_add, >> + .del = platform_pmu_event_del, >> + .start = platform_pmu_event_start, >> + .stop = platform_pmu_event_stop, >> + .read = platform_pmu_event_read, >> + .event_idx = platform_pmu_event_idx, >> + }; >> + >> + sprintf(axm_pmu->name, "LSI AXM55xx Platform"); >> + >> + ret = perf_pmu_register(&axm_pmu->pmu, axm_pmu->name, >> +PERF_TYPE_RAW); >> + >> + if (ret == 0) >> + pr_info("axxia platform perf enabled\n"); >> + else >> + pr_info("axxia platform perf failed\n"); >> + >> + vp_startup_init(); >> + pcx_startup_init(); >> + memc_startup_init(); >> + >> + return ret; >> +} >> + >> +static struct platform_driver axmperf_driver = { >> + .driver = { >> + .name = "AXM55xxPlatformPerf", >> + .owner = THIS_MODULE, >> + }, >> + .probe = axmperf_probe, >> +}; >> + >> +static int __init axmperf_init(void) { >> + platform_device_register(&axmperf_device); >> + platform_driver_register(&axmperf_driver); >> + >> + return 0; >> +} >> + >> +static void __exit axmperf_exit(void) { >> + pr_warn("AXM55xx platform perf exit!\n"); >> + platform_driver_unregister(&axmperf_driver); >> + platform_device_unregister(&axmperf_device); >> +} >> + >> +module_init(axmperf_init); >> +module_exit(axmperf_exit); >> +MODULE_LICENSE("GPL"); >> diff --git a/arch/arm/mach-axxia/perf_event_platform.h >> b/arch/arm/mach-axxia/perf_event_platform.h >> new file mode 100644 >> index 0000000..5446855 >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_platform.h >> @@ -0,0 +1,10 @@ >> + #define AXM55XX_R1 >> + >> +#define AXM_55XX_PLATFORM_BASE 0x10000 #define AXM_55XX_VP_BASE >> +(AXM_55XX_PLATFORM_BASE + 0x00) #define AXM_55XX_VP_MAX >> +(AXM_55XX_VP_BASE + 0x1fff) #define AXM_55XX_PCX_BASE >> +(AXM_55XX_PLATFORM_BASE + 0x4000) #define AXM_55XX_PCX_MAX >> +(AXM_55XX_PCX_BASE + 0x0fff) #define AXM_55XX_MEMC_BASE >> +(AXM_55XX_PLATFORM_BASE + 0x8000) #define AXM_55XX_MEMC_MAX >> +(AXM_55XX_MEMC_BASE + 0x0fff) #define AXM_55XX_PLATFORM_MAX >> +(AXM_55XX_MEMC_MAX) >> diff --git a/arch/arm/mach-axxia/perf_event_vp.c >> b/arch/arm/mach-axxia/perf_event_vp.c >> new file mode 100644 >> index 0000000..3993f24 >> --- /dev/null >> +++ b/arch/arm/mach-axxia/perf_event_vp.c >> @@ -0,0 +1,51 @@ >> +/* >> + * arch/arm/mach-axxia/perf_event_vp.c >> + * included from arch/arm/mach-axxia/perf_event_platform.c >> + * >> + * Support for the LSI Axxia boards based on ARM cores. >> + * >> + * Copyright (C) 2014 LSI >> + * >> + * This program is free software; you can redistribute it and/or >> +modify >> + * it under the terms of the GNU General Public License as published >> +by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> +02111-1307 USA */ >> + >> + >> +/* >> + * Generic VP >> + */ >> + >> +static void vp_startup_init(void) >> +{ >> +} >> + >> +static uint32_t vp_pmu_event_init(uint32_t event, struct perf_event >> +*pevent) { >> + return 0; >> +} >> + >> +static uint32_t vp_pmu_event_add(uint32_t event, struct perf_event >> +*pevent) { >> + return 0; >> +} >> + >> +static uint32_t vp_pmu_event_del(uint32_t event, struct perf_event *pevent, >> + int flags) >> +{ >> + return 0; >> +} >> + >> +static void vp_pmu_event_destroy(uint32_t event, struct perf_event >> +*pevent) { } >> diff --git a/arch/arm/mach-axxia/smon.c b/arch/arm/mach-axxia/smon.c >> new file mode 100644 index 0000000..b2f0a56 >> --- /dev/null >> +++ b/arch/arm/mach-axxia/smon.c >> @@ -0,0 +1,200 @@ >> +/* >> + * linux/arch/arm/mach-axxia/smon.c >> + * >> + * Platform perf helper module for generic VP statistical monitor >> + * >> + * Copyright (C) 2013 LSI Corporation. >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * version 2 as published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope that it will be useful, >> +but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA >> + * 02110-1301 USA >> + * >> + */ >> +#include <linux/io.h> >> + >> +#include <../../../drivers/misc/lsi-ncr.h> >> + >> +#include "smon.h" >> + >> +static void memcpy32_fromio(uint32_t *dest, uint32_t *src, uint32_t >> +len) { >> + uint32_t i; >> + >> + for (i = 0; i < len; i++) >> + dest[i] = ioread32(src + i); >> +} >> + >> +static void memcpy32_toio(uint32_t *dest, uint32_t *src, uint32_t >> +len) { >> + uint32_t i; >> + >> + for (i = 0; i < len; i++) >> + iowrite32(src[i], dest + i); >> +} >> + >> +void smon_init_ncp(struct smon_s *smon, uint32_t node, uint32_t target, >> + uint32_t offset) >> +{ >> + smon->assigned[0] = UNASSIGNED; >> + smon->assigned[1] = UNASSIGNED; >> + smon->type = NCP_SMON; >> + smon->node = node; >> + smon->target = target; >> + smon->offset = offset; >> +} >> + >> +void smon_init_mem(struct smon_s *smon, uint64_t addr, uint32_t >> +offset) { >> + smon->assigned[0] = UNASSIGNED; >> + smon->assigned[1] = UNASSIGNED; >> + smon->type = MEM_SMON; >> + smon->addr = ioremap(addr, SZ_4K); >> + smon->offset = offset; >> + >> + if (smon->addr == NULL) >> + pr_err("axxia perf, smon can't remap memory %lld\n", addr); } >> + >> +void smon_stop_if_unassigned(struct smon_s *smon) { >> + uint32_t control = 0; >> + >> + if (smon->assigned[0] == UNASSIGNED && >> + smon->assigned[1] == UNASSIGNED) { >> + ncr_write(NCP_REGION_ID(smon->node, smon->target), smon->offset, >> + 1 * REG_SZ, &control); >> + } >> +} >> + >> +uint32_t smon_allocate(struct smon_s *smon, uint8_t event) { >> + if (smon->assigned[0] == UNASSIGNED) { >> + smon->events[0] = event; >> + smon->assigned[0] = ASSIGNED; >> + } else if (smon->assigned[1] == UNASSIGNED) { >> + smon->events[1] = event; >> + smon->assigned[1] = ASSIGNED; >> + } else { >> + pr_warn("smon_allocate, no counter availible\n"); >> + return -ENOCOUNTER; >> + } >> + >> + return 0; >> +} >> + >> +uint32_t smon_deallocate(struct smon_s *smon, uint8_t event) { >> + if ((smon->assigned[0] == ASSIGNED) && (smon->events[0] == event)) >> + smon->assigned[0] = UNASSIGNED; >> + else if ((smon->assigned[1] == ASSIGNED) && (smon->events[1] == event)) >> + smon->assigned[1] = UNASSIGNED; >> + else >> + return -ENOCOUNTER; >> + >> + return 0; >> +} >> + >> +uint32_t smon_event_active(struct smon_s *smon, uint8_t event) { >> + if ((smon->assigned[0] == ASSIGNED) && (smon->events[0] == event)) >> + return 0; >> + else if ((smon->assigned[1] == ASSIGNED) && (smon->events[1] == event)) >> + return 0; >> + >> + return -ENOCOUNTER; >> +} >> + >> +uint32_t smon_read(struct smon_s *smon, uint8_t event) { >> + if (smon->type == NCP_SMON) >> + ncr_read(NCP_REGION_ID(smon->node, smon->target), smon->offset, >> + 8 * REG_SZ, &smon->regs); >> + else if (smon->type == MEM_SMON) >> + memcpy32_fromio((uint32_t *)&smon->regs, >> + (uint32_t *)smon->addr + smon->offset, 8); >> + >> + if ((smon->assigned[0] == ASSIGNED) && (smon->events[0] == event)) >> + return smon->regs.count0; >> + else if ((smon->assigned[1] == ASSIGNED) && (smon->events[1] == event)) >> + return smon->regs.count1; >> + >> + return -ENOEVENT; >> +} >> + >> +uint32_t smon_start(struct smon_s *smon, uint8_t event) { >> + /* get currect configuration */ >> + if (smon->type == NCP_SMON) >> + ncr_read(NCP_REGION_ID(smon->node, smon->target), smon->offset, >> + 8 * REG_SZ, &smon->regs); >> + else if (smon->type == MEM_SMON) >> + memcpy32_fromio((uint32_t *)&smon->regs, >> + (uint32_t *)smon->addr + smon->offset, 8); >> + >> + smon->regs.control = 1; /* run counters */ >> + >> + if ((smon->assigned[0] == ASSIGNED) && (smon->events[0] == event)) { >> + smon->regs.event0 = event; >> + smon->regs.count0 = 0; >> + >> + if (smon->type == NCP_SMON) { >> + /* write configuration, but do not change count reg */ >> + ncr_write(NCP_REGION_ID(smon->node, smon->target), >> + smon->offset, 2 * REG_SZ, &smon->regs); >> + >> + /* clear this events counter register */ >> + ncr_write(NCP_REGION_ID(smon->node, smon->target), >> + smon->offset + 4 * REG_SZ, 1 * REG_SZ, >> + &smon->regs.count0); >> + } else if (smon->type == MEM_SMON) { >> + /* write configuration, but do not change count reg */ >> + memcpy32_toio((uint32_t *)smon->addr + smon->offset, >> + (uint32_t *)&smon->regs, 2); >> + >> + /* clear this events counter register */ >> + memcpy32_toio((uint32_t *)smon->addr + smon->offset + 4, >> + (uint32_t *)&smon->regs.count0, 1); >> + >> + } >> + >> + } else if ((smon->assigned[1] == ASSIGNED) >> + && (smon->events[1] == event)) { >> + smon->regs.event1 = event; >> + smon->regs.count1 = 0; >> + >> + if (smon->type == NCP_SMON) { >> + /* write configuration, but do not change count reg */ >> + ncr_write(NCP_REGION_ID(smon->node, smon->target), >> + smon->offset, 2 * REG_SZ, &smon->regs); >> + >> + /* clear this events counter register */ >> + ncr_write(NCP_REGION_ID(smon->node, smon->target), >> + smon->offset + 5 * REG_SZ, 1 * REG_SZ, >> + &smon->regs.count1); >> + } else if (smon->type == MEM_SMON) { >> + /* write configuration, but do not change count reg */ >> + memcpy32_toio((uint32_t *)smon->addr + smon->offset, >> + (uint32_t *)&smon->regs, 2); >> + >> + /* clear this events counter register */ >> + memcpy32_toio((uint32_t *)smon->addr + smon->offset + 5, >> + (uint32_t *)&smon->regs.count1, 1); >> + } >> + >> + } else { >> + pr_warn("smon_start, no counter availible\n"); >> + return -ENOCOUNTER; >> + } >> + >> + return 0; >> +} >> diff --git a/arch/arm/mach-axxia/smon.h b/arch/arm/mach-axxia/smon.h >> new file mode 100644 index 0000000..bcdf39f >> --- /dev/null >> +++ b/arch/arm/mach-axxia/smon.h >> @@ -0,0 +1,71 @@ >> +/* >> + * Helper module for board specific I2C bus registration >> + * >> + * Copyright (C) 2014 LSI Corporation. >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * version 2 as published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope that it will be useful, >> +but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA >> + * 02110-1301 USA >> + * >> + */ >> +#ifndef __ASM__ARCH_AXXIA_SMON_H >> +#define __ASM__ARCH_AXXIA_SMON_H >> + >> +#include <linux/kernel.h> >> + >> +struct smon_reg_s { >> + uint32_t control; >> + uint8_t event0; >> + uint8_t event1; >> + uint16_t reserved; >> + uint32_t compare0; >> + uint32_t compare1; >> + uint32_t count0; >> + uint32_t count1; >> + uint32_t time; >> + uint32_t maxtime; >> +}; >> + >> +struct smon_s { >> + struct smon_reg_s regs; >> + uint32_t type; /* NCP_SMON or MEM_SMON */ >> + uint32_t *addr; /* MEM_SMON */ >> + uint32_t node; /* NCP_SMON */ >> + uint32_t target; /* " */ >> + uint32_t offset; >> + uint8_t assigned[2]; >> + uint8_t events[2]; >> +}; >> + >> +#define REG_SZ 4 >> + >> +#define MEM_SMON 0 >> +#define NCP_SMON 1 >> + >> +#define UNASSIGNED 0 >> +#define ASSIGNED 1 >> + >> +#define ENOCOUNTER 1 >> +#define ENOEVENT 2 >> + >> +void smon_init_ncp(struct smon_s *smon, uint32_t node, uint32_t target, >> + uint32_t offset); >> +void smon_init_mem(struct smon_s *smon, uint64_t addr, uint32_t >> +offset); void smon_stop_if_unassigned(struct smon_s *smon); uint32_t >> +smon_allocate(struct smon_s *smon, uint8_t event); uint32_t >> +smon_deallocate(struct smon_s *smon, uint8_t event); uint32_t >> +smon_event_active(struct smon_s *smon, uint8_t event); uint32_t >> +smon_read(struct smon_s *smon, uint8_t event); uint32_t >> +smon_start(struct smon_s *smon, uint8_t event); >> + >> +#endif /* __ASM__ARCH_AXXIA_SMON_H */ >> > > -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto