mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 05:34:00 +08:00
a5598ca0d4
The issue is the SPU code is not holding the kernel mutex lock while adding samples to the kernel buffer. This patch creates per SPU buffers to hold the data. Data is added to the buffers from in interrupt context. The data is periodically pushed to the kernel buffer via a new Oprofile function oprofile_put_buff(). The oprofile_put_buff() function is called via a work queue enabling the funtion to acquire the mutex lock. The existing user controls for adjusting the per CPU buffer size is used to control the size of the per SPU buffers. Similarly, overflows of the SPU buffers are reported by incrementing the per CPU buffer stats. This eliminates the need to have architecture specific controls for the per SPU buffers which is not acceptable to the OProfile user tool maintainer. The export of the oprofile add_event_entry() is removed as it is no longer needed given this patch. Note, this patch has not addressed the issue of indexing arrays by the spu number. This still needs to be fixed as the spu numbering is not guarenteed to be 0 to max_num_spus-1. Signed-off-by: Carl Love <carll@us.ibm.com> Signed-off-by: Maynard Johnson <maynardj@us.ibm.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Acked-by: Robert Richter <robert.richter@amd.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
169 lines
5.1 KiB
C
169 lines
5.1 KiB
C
/**
|
|
* @file oprofile.h
|
|
*
|
|
* API for machine-specific interrupts to interface
|
|
* to oprofile.
|
|
*
|
|
* @remark Copyright 2002 OProfile authors
|
|
* @remark Read the file COPYING
|
|
*
|
|
* @author John Levon <levon@movementarian.org>
|
|
*/
|
|
|
|
#ifndef OPROFILE_H
|
|
#define OPROFILE_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/spinlock.h>
|
|
#include <asm/atomic.h>
|
|
|
|
/* Each escaped entry is prefixed by ESCAPE_CODE
|
|
* then one of the following codes, then the
|
|
* relevant data.
|
|
* These #defines live in this file so that arch-specific
|
|
* buffer sync'ing code can access them.
|
|
*/
|
|
#define ESCAPE_CODE ~0UL
|
|
#define CTX_SWITCH_CODE 1
|
|
#define CPU_SWITCH_CODE 2
|
|
#define COOKIE_SWITCH_CODE 3
|
|
#define KERNEL_ENTER_SWITCH_CODE 4
|
|
#define KERNEL_EXIT_SWITCH_CODE 5
|
|
#define MODULE_LOADED_CODE 6
|
|
#define CTX_TGID_CODE 7
|
|
#define TRACE_BEGIN_CODE 8
|
|
#define TRACE_END_CODE 9
|
|
#define XEN_ENTER_SWITCH_CODE 10
|
|
#define SPU_PROFILING_CODE 11
|
|
#define SPU_CTX_SWITCH_CODE 12
|
|
#define IBS_FETCH_CODE 13
|
|
#define IBS_OP_CODE 14
|
|
|
|
struct super_block;
|
|
struct dentry;
|
|
struct file_operations;
|
|
struct pt_regs;
|
|
|
|
/* Operations structure to be filled in */
|
|
struct oprofile_operations {
|
|
/* create any necessary configuration files in the oprofile fs.
|
|
* Optional. */
|
|
int (*create_files)(struct super_block * sb, struct dentry * root);
|
|
/* Do any necessary interrupt setup. Optional. */
|
|
int (*setup)(void);
|
|
/* Do any necessary interrupt shutdown. Optional. */
|
|
void (*shutdown)(void);
|
|
/* Start delivering interrupts. */
|
|
int (*start)(void);
|
|
/* Stop delivering interrupts. */
|
|
void (*stop)(void);
|
|
/* Arch-specific buffer sync functions.
|
|
* Return value = 0: Success
|
|
* Return value = -1: Failure
|
|
* Return value = 1: Run generic sync function
|
|
*/
|
|
int (*sync_start)(void);
|
|
int (*sync_stop)(void);
|
|
|
|
/* Initiate a stack backtrace. Optional. */
|
|
void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
|
|
/* CPU identification string. */
|
|
char * cpu_type;
|
|
};
|
|
|
|
/**
|
|
* One-time initialisation. *ops must be set to a filled-in
|
|
* operations structure. This is called even in timer interrupt
|
|
* mode so an arch can set a backtrace callback.
|
|
*
|
|
* If an error occurs, the fields should be left untouched.
|
|
*/
|
|
int oprofile_arch_init(struct oprofile_operations * ops);
|
|
|
|
/**
|
|
* One-time exit/cleanup for the arch.
|
|
*/
|
|
void oprofile_arch_exit(void);
|
|
|
|
/**
|
|
* Add a sample. This may be called from any context. Pass
|
|
* smp_processor_id() as cpu.
|
|
*/
|
|
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event);
|
|
|
|
/**
|
|
* Add an extended sample. Use this when the PC is not from the regs, and
|
|
* we cannot determine if we're in kernel mode from the regs.
|
|
*
|
|
* This function does perform a backtrace.
|
|
*
|
|
*/
|
|
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
|
|
unsigned long event, int is_kernel);
|
|
|
|
/* Use this instead when the PC value is not from the regs. Doesn't
|
|
* backtrace. */
|
|
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event);
|
|
|
|
/* add a backtrace entry, to be called from the ->backtrace callback */
|
|
void oprofile_add_trace(unsigned long eip);
|
|
|
|
|
|
/**
|
|
* Create a file of the given name as a child of the given root, with
|
|
* the specified file operations.
|
|
*/
|
|
int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
|
|
char const * name, const struct file_operations * fops);
|
|
|
|
int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
|
|
char const * name, const struct file_operations * fops, int perm);
|
|
|
|
/** Create a file for read/write access to an unsigned long. */
|
|
int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
|
|
char const * name, ulong * val);
|
|
|
|
/** Create a file for read-only access to an unsigned long. */
|
|
int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
|
|
char const * name, ulong * val);
|
|
|
|
/** Create a file for read-only access to an atomic_t. */
|
|
int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
|
|
char const * name, atomic_t * val);
|
|
|
|
/** create a directory */
|
|
struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root,
|
|
char const * name);
|
|
|
|
/**
|
|
* Write the given asciz string to the given user buffer @buf, updating *offset
|
|
* appropriately. Returns bytes written or -EFAULT.
|
|
*/
|
|
ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset);
|
|
|
|
/**
|
|
* Convert an unsigned long value into ASCII and copy it to the user buffer @buf,
|
|
* updating *offset appropriately. Returns bytes written or -EFAULT.
|
|
*/
|
|
ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset);
|
|
|
|
/**
|
|
* Read an ASCII string for a number from a userspace buffer and fill *val on success.
|
|
* Returns 0 on success, < 0 on error.
|
|
*/
|
|
int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count);
|
|
|
|
/** lock for read/write safety */
|
|
extern spinlock_t oprofilefs_lock;
|
|
|
|
/**
|
|
* Add the contents of a circular buffer to the event buffer.
|
|
*/
|
|
void oprofile_put_buff(unsigned long *buf, unsigned int start,
|
|
unsigned int stop, unsigned int max);
|
|
|
|
unsigned long oprofile_get_cpu_buffer_size(void);
|
|
void oprofile_cpu_buffer_inc_smpl_lost(void);
|
|
|
|
#endif /* OPROFILE_H */
|