Other Parts Discussed in Thread: SK-AM62
Hi TI,
We use SK-AM62 EVM tested AM62x GPIO interrupt latency, and got below result, it is not good as expectation.
We measured that the maximum value would float to 144235 ns, which is much higher than the average value.
Is this reasonable?
How long does it take for a TI interruption to be normal? Has TI officially measured it?
The test RT Linux kernel version is 6.1.33-rt11(SDK 09_00_00_03).
The GPIO test code is attached, and use AM62x RT_Linux SDK base file system (tisdk-base-image).
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/rtmutex.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/cpumask.h>
#include <linux/interrupt.h>
#include <linux/ktime.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/kthread.h>
#include <linux/timekeeping.h>
#include <linux/sysfs.h>
// Module definition
#define MOD_License "GPL"
#define MOD_Author "MYTEST"
#define MOD_Description "IRQ measurement driver"
#define MOD_Version "1.0" // Format: Major.Minor = (0~255).(0~255)
int FPGA_IntrPinNum = 0;
#define FPGA_IntrPinName ( "FPGA IRQ" )
// The IRQ setting
#define IRQ_Name ( "FPGA Interrupt" )
#define IRQ_CPU_Affinity ( 0 )
static ktime_t irq_start_time;
static struct kobject *example_kobj = NULL;
static s64 irq_duration_ns = 0;
static s64 test_count = 0;
static s64 max_ns = 0;
static s64 min_ns = 0;
static s64 avg_ns = 0;
static irqreturn_t irq_handler(int irq, void *dev_id) {
irq_start_time = ktime_get();
return IRQ_WAKE_THREAD;
}
static irqreturn_t irq_thread_fn(int irq, void *data) {
ktime_t irq_end_time = ktime_get();
irq_duration_ns = ktime_to_ns(ktime_sub(irq_end_time, irq_start_time));
if(test_count==0)
{
test_count=1;
max_ns=irq_duration_ns;
min_ns=irq_duration_ns;
avg_ns=irq_duration_ns;
}
else
{
if(irq_duration_ns>max_ns)
{
max_ns=irq_duration_ns;
}
if(irq_duration_ns<min_ns)
{
min_ns=irq_duration_ns;
}
avg_ns= (avg_ns+irq_duration_ns)/2;
test_count++;
}
printk(KERN_ERR "count:%lld, cur:%lld ,max:%lld ,min:%lld , avg: %lld ns\n",test_count, irq_duration_ns,max_ns,min_ns,avg_ns);
return 0;
}
static int syntec_sysintrdrv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int nRst=0;
int kick_gpio = of_get_named_gpio_flags(np, "kick-gpios", 0, NULL);
FPGA_IntrPinNum = kick_gpio;
pr_err( "Get kick_gpio number= (%d)\n", FPGA_IntrPinNum );
//== Check the pin number is valid (return 0 if invalid)
if( gpio_is_valid( FPGA_IntrPinNum ) == 0 ) {
pr_info( "Invalid request for %s (%d)\n", FPGA_IntrPinName, FPGA_IntrPinNum );
return ( -EINVAL );
}
//== Request a GPIO
// If success return 0, otherwise return -EINVAL or -EBUSY
nRst = gpio_request( FPGA_IntrPinNum, FPGA_IntrPinName );
if( nRst != 0 ) {
pr_err( "MapIntrPinAndHandler FPGA_IntrPinNum= (%d)\n", FPGA_IntrPinNum );
pr_info( "GPIO request failed: %d\n", nRst );
return nRst;
}
//== Changing interface to gpiod API, but still need to free by using gpio API
// Note: the GPIO descriptor is not NULL, after request successfully
struct gpio_desc *pIntrPinDesc = gpio_to_desc( FPGA_IntrPinNum );
//== Set the interrupt pin as input
// The return value is zero for success, else a negative errno
nRst = gpiod_direction_input( pIntrPinDesc );
if( nRst != 0 ) {
gpio_free( FPGA_IntrPinNum );
pr_info( "Set GPIO be an input failed: %d\n", nRst );
return nRst;
}
//== Map GPIO number to IRQ number
// It will return an IRQ number, or a negative errno code if the mapping can't be done (most likely because that particular GPIO cannot be used as IRQ)
int nIRQNum = gpiod_to_irq( pIntrPinDesc );
if( nIRQNum < 0 ) {
gpio_free( FPGA_IntrPinNum );
pr_info( "The GPIO cannot be used as IRQ (Err: %d)\n", nIRQNum );
return nIRQNum;
}
//== Set IRQ interrupt affinity with specified CPU
struct cpumask tCpuMask = {};
cpumask_set_cpu( IRQ_CPU_Affinity, &tCpuMask );
nRst = irq_set_affinity_hint( nIRQNum, &tCpuMask );
if( nRst != 0 ) {
gpio_free( FPGA_IntrPinNum );
pr_info( "The IRQ number %d can not set CPU affinity (Err: %d)\n", nIRQNum, nRst );
return nRst;
}
//== Set IRQ signal trigger mode and copy handler data
unsigned long nIRQFlags =IRQF_TRIGGER_RISING | IRQF_NOBALANCING | IRQF_ONESHOT;
if (request_threaded_irq(nIRQNum, irq_handler, irq_thread_fn, nIRQFlags, IRQ_Name, NULL)) {
printk(KERN_ERR "Failed to register threaded IRQ handler\n");
return -EBUSY;
}
return 0;
}
static int syntec_sysintrdrv_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id syntec_sysintrdrv_of_match[] = {
{ .compatible = "mytest,sysintrdrv" },
{ }
};
MODULE_DEVICE_TABLE(of, mytest_sysintrdrv_of_match);
static struct platform_driver mytest_sysintrdrv_driver = {
.driver = {
.name = "mytest-SysIntrDrv",
.of_match_table = mytest_sysintrdrv_of_match,
},
.probe = mytest_sysintrdrv_probe,
.remove = mytest_sysintrdrv_remove,
};
int Module_fop_release( struct inode *pInode, struct file *pFile )
// The close operation of file system
{
// Do nothing...
return 0;
}
int __init Module_Init( void )
// Initialization when load module
{
int err;
pr_info( "Init %s (%s)\n", MOD_Description, MOD_Version );
err = platform_driver_register(&mytest_sysintrdrv_driver);
if (err < 0)
return err;
return 0;
}
void __exit Module_Exit( void )
// Release resource when unload module
{
platform_driver_unregister(&mytest_sysintrdrv_driver);
pr_info( "Release resource of %s (%s)\n", MOD_Description, MOD_Version );
}
module_init(Module_Init);
module_exit(Module_Exit);
MODULE_LICENSE( MOD_License );
MODULE_AUTHOR( MOD_Author );
MODULE_DESCRIPTION( MOD_Description );
MODULE_VERSION( MOD_Version );