summaryrefslogblamecommitdiffstats
blob: a8b9e7d61eceacf398c9ebe70bde67135a2581b1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   
                                                            













                                                                       




                                                                    

                                   

      








                                                            
                                                   

                                           
 






                           
 

                         


                      
                  
                          



                              

                                                                                     
 





                                                                               




















                                                                                           
 
              

                  



                                           
                          
                                   
                    

                                                            
         
                                           

                     
                                                                        


         
                                                 
 
              
                  
                              

                         




                                                   

                       

                                         
                    

                                                                 
         
                                           
 
                                                       
                    
                                                                                  

         



















                                                                                                       
      
 
                                                        
                                  
 




                                                         









                              





                                                                                                          

                                                     

  

                              




                                                                                                                                                             

                                                                              
 



                                                     


                                                                                      

                                                                                              


                                                                                                                  




                                                     


                                                                            
                                                                                              


                                                                                                        






                                                                  
                                                                                 
                                                                         
                         

                      
 






                                                        


                              


                                                                                                                                    
                                                                                                              
      
 
                                            


                                          
 

                                                                              
 
                            








                                   

                                     

         

                                    
                                      


                                                                                                                   

                                     



                                                                                                             
                              
                 
         


      
                                      
 
          
                                                  


                                                      
                         
                                                             

                                                                             
 
                                                        
                                                                      


                                                         

      
                                                        
                                                                      


                                                          

      


                 
                                      
 

                                                        

                                                            
      






                                                             
                                                                             
 
/**
 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
 *
 * 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.
 */

#include "gator.h"

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/math64.h>

#ifdef MALI_SUPPORT
#ifdef MALI_DIR_MIDGARD
/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
#include "mali_linux_trace.h"
#else
/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
#include "linux/mali_linux_trace.h"
#endif
#endif

/*
 * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK.
 */
#define EVENT_TYPE_SINGLE  0
#define EVENT_TYPE_START   1
#define EVENT_TYPE_STOP    2
#define EVENT_TYPE_SUSPEND 3
#define EVENT_TYPE_RESUME  4

/* Note whether tracepoints have been registered */
static int mali_timeline_trace_registered;
static int mali_job_slots_trace_registered;

enum {
	GPU_UNIT_NONE = 0,
	GPU_UNIT_VP,
	GPU_UNIT_FP,
	GPU_UNIT_CL,
	NUMBER_OF_GPU_UNITS
};

#if defined(MALI_SUPPORT)

struct mali_activity {
	int core;
	int key;
	int count;
	int last_activity;
	int last_pid;
};

#define NUMBER_OF_GPU_CORES 16
static struct mali_activity mali_activities[NUMBER_OF_GPU_UNITS*NUMBER_OF_GPU_CORES];
static DEFINE_SPINLOCK(mali_activities_lock);

/* Only one event should be running on a unit and core at a time (ie, a start
 * event can only be followed by a stop and vice versa), but because the kernel
 * only knows when a job is enqueued and not started, it is possible for a
 * start1, start2, stop1, stop2. Change it back into start1, stop1, start2,
 * stop2 by queueing up start2 and releasing it when stop1 is received.
 */

static int mali_activity_index(int core, int key)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(mali_activities); ++i) {
		if ((mali_activities[i].core == core) && (mali_activities[i].key == key)) {
			break;
		}
		if ((mali_activities[i].core == 0) && (mali_activities[i].key == 0)) {
			mali_activities[i].core = core;
			mali_activities[i].key = key;
			break;
		}
	}
	BUG_ON(i >= ARRAY_SIZE(mali_activities));

	return i;
}

static void mali_activity_enqueue(int core, int key, int activity, int pid)
{
	int i;
	int count;

	spin_lock(&mali_activities_lock);
	i = mali_activity_index(core, key);

	count = mali_activities[i].count;
	BUG_ON(count < 0);
	++mali_activities[i].count;
	if (count) {
		mali_activities[i].last_activity = activity;
		mali_activities[i].last_pid = pid;
	}
	spin_unlock(&mali_activities_lock);

	if (!count) {
		gator_marshal_activity_switch(core, key, activity, pid);
	}
}

static void mali_activity_stop(int core, int key)
{
	int i;
	int count;
	int last_activity = 0;
	int last_pid = 0;

	spin_lock(&mali_activities_lock);
	i = mali_activity_index(core, key);

	if (mali_activities[i].count == 0) {
		spin_unlock(&mali_activities_lock);
		return;
	}
	--mali_activities[i].count;
	count = mali_activities[i].count;
	if (count) {
		last_activity = mali_activities[i].last_activity;
		last_pid = mali_activities[i].last_pid;
	}
	spin_unlock(&mali_activities_lock);

	gator_marshal_activity_switch(core, key, 0, 0);
	if (count) {
		gator_marshal_activity_switch(core, key, last_activity, last_pid);
	}
}

void mali_activity_clear(mali_counter mali_activity[], size_t mali_activity_size)
{
	int activity;
	int cores;
	int core;

	for (activity = 0; activity < mali_activity_size; ++activity) {
		cores = mali_activity[activity].cores;
		if (cores < 0) {
			cores = 1;
		}
		for (core = 0; core < cores; ++core) {
			if (mali_activity[activity].enabled) {
				gator_marshal_activity_switch(core, mali_activity[activity].key, 0, 0);
			}
		}
	}
}

#endif

#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
#include "gator_events_mali_4xx.h"

/*
 * Taken from MALI_PROFILING_EVENT_CHANNEL_* in Mali DDK.
 */
enum {
	EVENT_CHANNEL_SOFTWARE = 0,
	EVENT_CHANNEL_VP0 = 1,
	EVENT_CHANNEL_FP0 = 5,
	EVENT_CHANNEL_FP1,
	EVENT_CHANNEL_FP2,
	EVENT_CHANNEL_FP3,
	EVENT_CHANNEL_FP4,
	EVENT_CHANNEL_FP5,
	EVENT_CHANNEL_FP6,
	EVENT_CHANNEL_FP7,
	EVENT_CHANNEL_GPU = 21
};

/**
 * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel
 */
enum {
	EVENT_REASON_SINGLE_GPU_NONE = 0,
	EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1,
};

mali_counter mali_activity[2];

GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
{
	unsigned int component, state;

	// do as much work as possible before disabling interrupts
	component = (event_id >> 16) & 0xFF;	// component is an 8-bit field
	state = (event_id >> 24) & 0xF;	// state is a 4-bit field

	switch (state) {
	case EVENT_TYPE_START:
		if (component == EVENT_CHANNEL_VP0) {
			/* tgid = d0; pid = d1; */
			if (mali_activity[1].enabled) {
				mali_activity_enqueue(0, mali_activity[1].key, 1, d1);
			}
		} else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
			/* tgid = d0; pid = d1; */
			if (mali_activity[0].enabled) {
				mali_activity_enqueue(component - EVENT_CHANNEL_FP0, mali_activity[0].key, 1, d1);
			}
		}
		break;

	case EVENT_TYPE_STOP:
		if (component == EVENT_CHANNEL_VP0) {
			if (mali_activity[1].enabled) {
				mali_activity_stop(0, mali_activity[1].key);
			}
		} else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
			if (mali_activity[0].enabled) {
				mali_activity_stop(component - EVENT_CHANNEL_FP0, mali_activity[0].key);
			}
		}
		break;

	case EVENT_TYPE_SINGLE:
		if (component == EVENT_CHANNEL_GPU) {
			unsigned int reason = (event_id & 0xffff);

			if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) {
				gator_events_mali_log_dvfs_event(d0, d1);
			}
		}
		break;

	default:
		break;
	}
}
#endif

#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)

mali_counter mali_activity[3];

#if defined(MALI_JOB_SLOTS_EVENT_CHANGED)
GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id))
#else
GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid))
#endif
{
	unsigned int component, state, unit;
#if !defined(MALI_JOB_SLOTS_EVENT_CHANGED)
	unsigned char job_id = 0;
#endif

	component = (event_id >> 16) & 0xFF;	// component is an 8-bit field
	state = (event_id >> 24) & 0xF;	// state is a 4-bit field

	switch (component) {
	case 0:
		unit = GPU_UNIT_FP;
		break;
	case 1:
		unit = GPU_UNIT_VP;
		break;
	case 2:
		unit = GPU_UNIT_CL;
		break;
	default:
		unit = GPU_UNIT_NONE;
	}

	if (unit != GPU_UNIT_NONE) {
		switch (state) {
		case EVENT_TYPE_START:
			if (mali_activity[component].enabled) {
				mali_activity_enqueue(0, mali_activity[component].key, 1, (pid != 0 ? pid : tgid));
			}
			break;
		case EVENT_TYPE_STOP:
		default: // Some jobs can be soft-stopped, so ensure that this terminates the activity trace.
			if (mali_activity[component].enabled) {
				mali_activity_stop(0, mali_activity[component].key);
			}
			break;
		}
	}
}
#endif

static int gator_trace_gpu_start(void)
{
	/*
	 * Returns nonzero for installation failed
	 * Absence of gpu trace points is not an error
	 */

#if defined(MALI_SUPPORT)
	memset(&mali_activities, 0, sizeof(mali_activities));
#endif
	mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;

#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
	mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
	if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
		mali_timeline_trace_registered = 1;
	}
#endif

#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
	mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
	if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) {
		mali_job_slots_trace_registered = 1;
	}
#endif

	return 0;
}

static void gator_trace_gpu_stop(void)
{
#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
	if (mali_timeline_trace_registered) {
		GATOR_UNREGISTER_TRACE(mali_timeline_event);
	}
#endif

#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
	if (mali_job_slots_trace_registered) {
		GATOR_UNREGISTER_TRACE(mali_job_slots_event);
	}
#endif

	mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
}