mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
From: Tim Sander <tim@krieglstein.org>
To: ptxdist@pengutronix.de
Subject: [ptxdist] am335x latency
Date: Thu, 28 Mar 2013 09:31:35 +0100	[thread overview]
Message-ID: <3389134.qVaFbxesDi@dabox> (raw)
In-Reply-To: <20130327081300.GI1366@pengutronix.de>

[-- Attachment #1: Type: text/plain, Size: 856 bytes --]

Hi

Am Mittwoch, 27. März 2013, 09:13:00 schrieb Robert Schwebel:
> On Wed, Mar 27, 2013 at 08:24:21AM +0100, Tim Sander wrote:
> > I have tested with 3.2.32-rt51 and when floodpinging the latency in a
> > kernel driver(! not even usermode) was in the range of milliseconds?
> > Have you tested flood pinging with the newer kernel?
> 
> We just got it running yesterday, more tests will come.
I have tested the interrupt latency in kernel with a module which is attached. 
This uses the am335x timers to measure the latency into usermode and after 
interrupt. The code is attached. Just compile the module and start up the 
usermode helper which prints out the measured latencies.

Could you possibly send me the kernelconfig of the 3.6 rt setup? I would like 
to test the new rt kernel but somehow my kconfig is borked.

Best regards
Tim

[-- Attachment #2: firq.c --]
[-- Type: text/x-csrc, Size: 13371 bytes --]

/*
 * FIRQ interrupt latency test
 *
 * 2010 (C) Tim Sander <tim.sander@hbm.com>
 *
 * 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.
 *
 */

#define DEBUG

#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/io.h>
#include <linux/version.h>
#include <mach/hardware.h>
#include <plat/dmtimer.h>

#define DRV_NAME	"firq"

#define TIMER_RELOAD			0xffffffff-10000000u
#define FIRQ_DEVICES			(2)
#define FIRQ_FIFO_SIZE			64
#define IOMEM_BASE				0x48044000
#define IOMEM_LEN				0xFFFF+1


struct firq_priv;

struct irq_stat {
	unsigned int min;
	unsigned int max;
	unsigned int avg;
};

struct firq_misc {
	int			minor;
	atomic_t		free;
	struct firq_priv		*priv;
};

struct firq_priv {
	struct omap_dm_timer	*timer;
	int	 					irq;
	struct platform_device	*pdev;
    struct kfifo			fifos[FIRQ_DEVICES];
    wait_queue_head_t		wqs[FIRQ_DEVICES];
	struct firq_misc		misc[FIRQ_DEVICES];
	struct irq_stat			irqstat;
	struct irq_stat			userstat;
	struct task_struct 		*wakeupTask;
	int 					maxlatency;
};

void init_irq_statistics(struct irq_stat *irq) {
	irq->min=0xffffffff;
	irq->max=0;
	irq->avg=1;
}

void update_irq_statistics(unsigned int tval,unsigned int rval,struct irq_stat *irq) {
	unsigned int real = tval - rval;
	if(real>irq->max) irq->max=real;
	if(real<irq->min) irq->min=real;
	irq->avg=(irq->avg*7+real)>>3;
}

static struct firq_priv	*current_instance;

static inline int firq_get_device_no(struct firq_priv *priv, struct firq_misc *misc)
{
	return misc - priv->misc;
}

static int firq_misc_get(struct firq_priv *priv, struct inode *inode, struct firq_misc **ret_misc)
{
	struct firq_misc *misc;
	int minor = iminor(inode);
	int i;

	dev_dbg(&priv->pdev->dev, "%s: minor: %d\n", __func__, minor);

	for (i = 0; i < ARRAY_SIZE(priv->misc); i++) {
		misc = &priv->misc[i];

		dev_dbg(&priv->pdev->dev, "%s: misc->minor: %d, free %d\n", __func__, misc->minor, atomic_read(&misc->free));

		if (misc->minor == minor) {
			if (!atomic_sub_and_test(1, &misc->free)) {
				atomic_inc(&misc->free);
				return -EBUSY;
			}

			dev_dbg(&priv->pdev->dev, "%s: using device #%d\n", __func__, i);

			*ret_misc = misc;
			return 0;
		}
	}

	return -ENODEV;
}

static int firq_misc_put(struct firq_priv *priv, struct firq_misc *misc)
{
	atomic_inc(&misc->free);

	return 0;
}

static int firq_open(struct inode *inode, struct file *file)
{
	struct firq_priv *priv = current_instance;
	struct firq_misc *misc;
	int err;

	err = firq_misc_get(priv, inode, &misc);
	if (err)
		return err;

	file->private_data = misc;

	//initialize iomem mapping here
	return 0;
}

static int firq_release(struct inode *inode, struct file *file)
{
	struct firq_misc *misc = file->private_data;
	struct firq_priv *priv = misc->priv;

	firq_misc_put(priv, misc);
	//free io

	return 0;
}

static ssize_t firq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	unsigned long retval;
    //unsigned lenout;
	struct firq_misc *misc = file->private_data;
	struct firq_priv *priv = misc->priv;
	//int device_number = firq_get_device_no(priv, misc);

	priv->wakeupTask=current;
	set_current_state(TASK_INTERRUPTIBLE);
	schedule();

	update_irq_statistics(ioread32(((void*)priv->timer->io_base)+0x3C),ioread32(((void*)priv->timer->io_base)+0x40),&(priv->userstat));
	retval=copy_to_user(buf,&priv->irqstat,sizeof(priv->irqstat));
	__set_current_state(TASK_RUNNING);

	return retval;
}

static ssize_t firq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	struct firq_misc *misc = file->private_data;
	struct firq_priv *priv = misc->priv;
	int res;
	unsigned int maxlatency;
	char inbuffer[10];
    res=copy_from_user(inbuffer,buf,count<10?count:10);
	if(res) {
		return res;
	}
	inbuffer[9]=0;
	if(strncmp("clear",inbuffer,5)==0) {
		init_irq_statistics(&(priv->userstat));
		init_irq_statistics(&(priv->irqstat));
	} else {
		sscanf(inbuffer,"%u",&maxlatency);
		dev_info(&priv->pdev->dev,"maxlatency:%i\n",maxlatency);
		priv->maxlatency=maxlatency;
		tracing_on();
	}
	return count;
}

static unsigned int firq_poll(struct file *file,poll_table *wait) {
	/*
	struct firq_misc *misc = file->private_data;
	struct firq_priv *priv = misc->priv;
	unsigned int mask=0;
	int device_number = firq_get_device_no(priv, misc);
	dev_dbg(&priv->pdev->dev, "%s: using device #%d poll_wait\n", __func__, device_number);
	poll_wait(file,&priv->wqs[device_number],wait);
	if(kfifo_len(&priv->fifos[device_number])) { //we have data available for reading
		mask |= POLLIN |POLLRDNORM; 
	}
	if((FIRQ_FIFO_SIZE/2-ioread32(&priv->fpga->regsGeneral.fifoCpuToMspCount))>0) { //we have space in input buffer
		mask |= POLLOUT |POLLWRNORM;                                   //for writing
	}
	return mask;
	*/
	return 0;
}

static int firq_mmap(struct file *file, struct vm_area_struct *vma) {
	int size=vma->vm_end-vma->vm_start;
	if(size>IOMEM_LEN) {
		return -EINVAL;
	}
	vma->vm_flags |= VM_IO |VM_RESERVED;
	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
	if(remap_pfn_range(vma, vma->vm_start, IOMEM_BASE>>PAGE_SHIFT, size, vma->vm_page_prot)) {
		printk(KERN_INFO "firq: mmap of timer registers failed.");
		return -EAGAIN;
	};
	return 0;
}

static irqreturn_t firq_irq_handler(int irq,void *data) {
	struct firq_priv *priv = data;
	unsigned int tval,rval;
	//clear interrupt flag
	iowrite32(0x2,priv->timer->io_base+0x28);
	tval=ioread32(((void*)priv->timer->io_base)+0x3C);
	rval=ioread32(((void*)priv->timer->io_base)+0x40);
	update_irq_statistics(tval,rval,&(priv->irqstat));
	if(priv->maxlatency<(tval-rval)) {
		tracing_off();
		priv->maxlatency=0;
	}
	if(current_instance->wakeupTask) wake_up_process(current_instance->wakeupTask);

	return IRQ_HANDLED;
}

static struct file_operations firq_fops = {
	.owner		= THIS_MODULE,
	.open		= firq_open,
	.release	= firq_release,
	.read		= firq_read,
	.write		= firq_write,
	//.poll		= firq_poll,
	.mmap		= firq_mmap,
};

static struct file_operations firq_latency_fops = {
	.open		= firq_open,
	.release	= firq_release,
	.write		= firq_write,
};

static struct miscdevice firq_miscdev[] = {
	{
		.minor	= MISC_DYNAMIC_MINOR,
		.name	= "firq",
		.fops	= &firq_fops,
	},
	{
		.minor	= MISC_DYNAMIC_MINOR,
		.name	= "firqlatency",
		.fops	= &firq_latency_fops,
	},
};

static int firq_probe_cdev(struct platform_device *pdev)
{
	struct firq_priv *priv = platform_get_drvdata(pdev);
	int i=0, err,have_misc=0;
	dev_info(&pdev->dev, "nr of devices: %i",ARRAY_SIZE(firq_miscdev));
	for (i = 0; i < ARRAY_SIZE(firq_miscdev); i++) { 
		init_waitqueue_head(&priv->wqs[i]);
		err = misc_register(&firq_miscdev[i]);
		if (err) goto exit_unregister;
		have_misc=1;

		priv->misc[i].minor = firq_miscdev[i].minor;
		priv->misc[i].priv = priv;
		atomic_set(&priv->misc[i].free, 1);

		dev_info(&pdev->dev, "registered %s with minor %d\n", firq_miscdev[i].name, firq_miscdev[i].minor);
   		err=kfifo_alloc(&priv->fifos[i],FIRQ_FIFO_SIZE,GFP_KERNEL); 
		if(err) goto exit_unregister;
		have_misc=0;

	}

	return 0;

 exit_unregister:
	printk("ERROR IN CDEV\n");
	for (i--; i >= 0; i--) {
		kfifo_free(&priv->fifos[i]);
		if(have_misc) misc_deregister(&firq_miscdev[i]);
		have_misc=1;
	}

	return err;
}

static int firq_probe(struct platform_device *pdev)
{
	struct firq_priv *priv;
	struct resource *res;
	void __iomem *base;
	int err, irq;
	char *cm_per;
	
	dev_info(&pdev->dev, "%s\n", __func__);
	if (current_instance)
		return -EBUSY;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	
	if (!res) {
		dev_info(&pdev->dev, "%s probe failed on resource register.\n", __func__);
		err = -ENODEV;
		goto exit;
	}

	/* requesting region collides with fpga driver, but we want both drivers access the same region
	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
		pr_err("firq driver request region failed");
		err = -EBUSY;
		goto exit;
	}
	*/

	base = ioremap(res->start, resource_size(res));
	if (!base) {
		dev_err(&pdev->dev, "%s error: failed to map memory",__func__);
		err = -ENOMEM;
		goto exit;
	}

	priv = kzalloc(sizeof(struct firq_priv), GFP_KERNEL);
	if (!priv) {
		dev_err(&pdev->dev, "%s error: failed to allocate memory",__func__);
		err = -ENOMEM;
		goto exit_iounmap;
	}
	init_irq_statistics(&(priv->irqstat));
	init_irq_statistics(&(priv->userstat));
	priv->wakeupTask=NULL;

	platform_set_drvdata(pdev, priv);
	priv->pdev = pdev;

	current_instance = priv;
	
	//get clock module peripheral registers
	cm_per = ioremap(0x44E00000,1024);
	if(cm_per) {
		dev_info(&priv->pdev->dev,"switch mux to high speed clock timer 4\n");
		iowrite32(1,cm_per+0x10); //enable high speed clock on timer 4
		iounmap(cm_per);
	}
	//priv->timer = omap_dm_timer_request();
	priv->timer = omap_dm_timer_request_specific(4);
	if(priv->timer==0) goto exit_free;
	irq = omap_dm_timer_get_irq(priv->timer);
	omap_dm_timer_set_int_enable(priv->timer,OMAP_TIMER_INT_OVERFLOW);
	omap_dm_timer_enable(priv->timer);
	//omap_dm_timer_set_source(priv->timer,OMAP_TIMER_SRC_SYS_CLK); //does not work?
	//omap_dm_timer_set_source(priv->timer,OMAP_TIMER_SRC_32_KHZ);
	omap_dm_timer_set_pwm(priv->timer,1,0,OMAP_TIMER_TRIGGER_OVERFLOW);
	omap_dm_timer_set_prescaler(priv->timer,0);
	omap_dm_timer_set_load_start(priv->timer,1,TIMER_RELOAD);
	iowrite32(0x2,((void*)priv->timer->io_base)+0x2c);
	dev_info(&priv->pdev->dev,"iobase: %x\n",(unsigned int)priv->timer->io_base);
	dev_info(&priv->pdev->dev,"func_base: %x\n",(unsigned int)priv->timer->func_base);
	dev_info(&priv->pdev->dev,"irqstatus raw: %x\n",ioread32(((void*)priv->timer->io_base)+0x24));
	dev_info(&priv->pdev->dev,"irqstatus: %x\n",ioread32(((void*)priv->timer->io_base)+0x28));
	dev_info(&priv->pdev->dev,"irqenable: %x\n",ioread32(((void*)priv->timer->io_base)+0x2c));
	dev_info(&priv->pdev->dev,"timer status: %x\n",ioread32(((void*)priv->timer->io_base)+0x18));
	dev_info(&priv->pdev->dev,"timer control: %x\n",ioread32(((void*)priv->timer->io_base)+0x38));
	dev_info(&priv->pdev->dev,"timer count: %x\n",ioread32(((void*)priv->timer->io_base)+0x3C));
	dev_info(&priv->pdev->dev,"timer load: %x\n",ioread32(((void*)priv->timer->io_base)+0x40));

	priv->irq = irq;
	if(request_irq(irq,firq_irq_handler,IRQF_SHARED|IRQF_TRIGGER_LOW,"firq-timer",current_instance)) {
		dev_err(&pdev->dev, "error: failed to allocate interrupt.");
		err = - ENODEV;
		goto exit_timer;
	}
	
	//enable_irq(irq);
	err = firq_probe_cdev(pdev);
	if (err) goto exit_irq;

	return 0;
 exit_irq:
	free_irq(irq,pdev);
 exit_timer:
	omap_dm_timer_free(priv->timer);
 exit_free:
	kfree(priv);
 exit_iounmap:
	iounmap(base);
	/*
 exit_release:
	release_mem_region(res->start, resource_size(res));
	*/
 exit:
	return err;
}

static void firq_remove_cdev(struct platform_device *pdev)
{
	int i=0;

	for (i = ARRAY_SIZE(firq_miscdev) - 1; i >= 0; i--)
		misc_deregister(&firq_miscdev[i]);
}

static int firq_remove(struct platform_device *pdev)
{
	struct firq_priv *priv = platform_get_drvdata(pdev);
	struct resource *res;

	disable_irq(priv->irq);
	firq_remove_cdev(pdev);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	//release_mem_region(res->start, resource_size(res));

	current_instance = NULL;

	kfree(priv);

	return 0;
}

static struct platform_driver firq_driver = {
	.probe		= firq_probe,
	.remove		= firq_remove,
	.driver.name	= DRV_NAME,
};


/* this should go into the board file - START - */

static struct resource firq_resources[] = {
	{
		.start	= IOMEM_BASE,
		.end	= IOMEM_BASE + IOMEM_LEN - 1,
		.flags	= IORESOURCE_MEM,
	},
};

/* not needed in board file */
static void firq_plat_release(struct device *dev)
{
	dev_info(dev, "%s\n", __func__);
}

static struct platform_device firq_device = {
	.name		= DRV_NAME,
	.id		= -1,
	.resource	= firq_resources,
	.num_resources	= ARRAY_SIZE(firq_resources),
	.dev.release	= firq_plat_release,
};

static int firq_device_register(void)
{
	return platform_device_register(&firq_device);
}

/* not needed in board file */
static void firq_device_unregister(void)
{
	platform_device_unregister(&firq_device);
}

/* this should go into the board file - END - */


static int __init firq_init(void)
{
	int err;

	pr_info("%s driver loaded\n", DRV_NAME);

	err = firq_device_register();
	if (err)
		goto exit;

	err = platform_driver_register(&firq_driver);
	if (err) {
		dev_info(NULL,"%s platform register failed\n",DRV_NAME);
		goto exit_unregister;
	}


	return 0;
 exit_unregister:
	firq_device_unregister();
 exit:
	return err;
}

static void __exit firq_exit(void)
{
	firq_device_unregister();
	platform_driver_unregister(&firq_driver);
	pr_info("%s driver removed\n", DRV_NAME);
}

module_init(firq_init);
module_exit(firq_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("firq serial driver");
MODULE_AUTHOR("Tim Sander");
MODULE_ALIAS("devname:firq");
MODULE_ALIAS("platform:firq");

[-- Attachment #3: firqreader.c --]
[-- Type: text/x-csrc, Size: 2681 bytes --]

#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <pthread.h>

#define MMAP_LEN	1024
#define FPGA_DEV "/dev/firq"

struct irq_tstat {
	unsigned int min;
	unsigned int max;
	unsigned int avg;
};
//global variables for thread
pthread_mutex_t slowThreadMutex;
int finish=0;
int firq_dev;
void *mmap_base;
struct irq_tstat is;
struct irq_tstat tstat;

void outputStat(const char *mode,struct irq_tstat val) {
	float tcl = .00000004000000000000;
	printf("%s min:%.9f max:%.9f avg:%.9f\n",mode,val.min*tcl,val.max*tcl,val.avg*tcl);
}

void sighandler(int signum) {
	finish=1;
}

static void *rtthread(void *arg) {
	while(!finish) {
		read(firq_dev,&is,sizeof(is));
		unsigned int counter = *((unsigned int*)(mmap_base+0x3C));
		unsigned int reload = *((unsigned int*)(mmap_base+0x40));
		unsigned diff = counter - reload;
		if(tstat.min>diff) tstat.min=diff;
		if(tstat.max<diff) tstat.max=diff;
		tstat.avg = (tstat.avg+diff)>>1;
		pthread_mutex_unlock(&slowThreadMutex);
	}
}

int main(int argc,char* argv[]) {
	pthread_mutexattr_t mutexattr;
	pthread_attr_t rtattr;
	pthread_t tid;
	struct sched_param params;
	struct sigaction action;
	unsigned char c;
	unsigned short s;
	unsigned int   w;
	int address;
	char access;
	char *endptr;
	int res;
	int i;
	struct sched_param param;
	tstat.min=0xffffffff;
	tstat.max=0;
	tstat.avg=1;
	printf("threaded version:1\n");

	firq_dev=open(FPGA_DEV,O_RDWR);
	if(firq_dev==-1) {
		perror(FPGA_DEV);
		exit(1);
	};
	mmap_base=mmap(0,MMAP_LEN,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_LOCKED,firq_dev,0);
	if((int)mmap_base==-1) {
		perror("mmap");
		exit(2);
	}
	for(i=0;i<20;i++) {
		action.sa_handler=sighandler;
		sigaction(i,&action,NULL);
	}
	pthread_mutexattr_init (&mutexattr);
	//pthread_mutexattr_setprotocol (&mutexattr, PTHREAD_PRIO_NONE);
	pthread_mutex_init(&slowThreadMutex,&mutexattr);
	pthread_attr_init(&rtattr);
	pthread_attr_setschedpolicy(&rtattr, SCHED_FIFO);
	params.sched_priority = 98;
	pthread_attr_setschedparam(&rtattr, &params);
	pthread_create(&tid,&rtattr,rtthread,NULL);
	/*
	param.sched_priority=98;
	if(sched_setscheduler(0,SCHED_FIFO,&param) == -1) {
		perror("MeasThread::run(), sched_setscheduler");
		exit(-1);
	}
	*/
	
	while(!finish) {
		pthread_mutex_lock(&slowThreadMutex);
		outputStat("rusermode",tstat);
		outputStat("rirq     ",is);
		printf("usermode  min:%u max:%u avg:%u\n",tstat.min,tstat.max,tstat.avg);
		printf("irq       min:%u max:%u avg:%u\n",is.min,is.max,is.avg);
	}
	res=munmap(mmap_base,MMAP_LEN);
	close(firq_dev);
   return 0;
}

[-- Attachment #4: Type: text/plain, Size: 48 bytes --]

-- 
ptxdist mailing list
ptxdist@pengutronix.de

      reply	other threads:[~2013-03-28  8:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-26 13:40 [ptxdist] Patch Kernet with preempt_rt patch "Breixo López García"
2013-03-26 13:52 ` Bernhard Walle
2013-03-26 14:02 ` "Breixo López García"
2013-03-26 23:56 ` Robert Schwebel
2013-03-27  7:24   ` Tim Sander
2013-03-27  8:13     ` Robert Schwebel
2013-03-28  8:31       ` Tim Sander [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3389134.qVaFbxesDi@dabox \
    --to=tim@krieglstein.org \
    --cc=ptxdist@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox