From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from lvps176-28-13-145.dedicated.hosteurope.de ([176.28.13.145]) by metis.ext.pengutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1UL8FE-0001HY-Sn for ptxdist@pengutronix.de; Thu, 28 Mar 2013 09:31:39 +0100 Received: from dabox.localnet (unknown [62.159.134.147]) by lvps176-28-13-145.dedicated.hosteurope.de (Postfix) with ESMTPSA id 40175A8A4026 for ; Thu, 28 Mar 2013 09:31:36 +0100 (CET) From: Tim Sander Date: Thu, 28 Mar 2013 09:31:35 +0100 Message-ID: <3389134.qVaFbxesDi@dabox> In-Reply-To: <20130327081300.GI1366@pengutronix.de> References: <5093873.psrJHpX9u8@dabox> <20130327081300.GI1366@pengutronix.de> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart2012892.YpTzI8U3FO" Content-Transfer-Encoding: 7Bit Subject: [ptxdist] am335x latency Reply-To: ptxdist@pengutronix.de List-Id: PTXdist Development Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ptxdist-bounces@pengutronix.de Errors-To: ptxdist-bounces@pengutronix.de To: ptxdist@pengutronix.de This is a multi-part message in MIME format. --nextPart2012892.YpTzI8U3FO Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" Hi Am Mittwoch, 27. M=E4rz 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? >=20 > We just got it running yesterday, more tests will come. I have tested the interrupt latency in kernel with a module which is at= tached.=20 This uses the am335x timers to measure the latency into usermode and af= ter=20 interrupt. The code is attached. Just compile the module and start up t= he=20 usermode helper which prints out the measured latencies. Could you possibly send me the kernelconfig of the 3.6 rt setup? I woul= d like=20 to test the new rt kernel but somehow my kconfig is borked. Best regards Tim --nextPart2012892.YpTzI8U3FO Content-Disposition: attachment; filename="firq.c" Content-Transfer-Encoding: 7Bit Content-Type: text/x-csrc; charset="UTF-8"; name="firq.c" /* * FIRQ interrupt latency test * * 2010 (C) Tim Sander * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(realmin) 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"); --nextPart2012892.YpTzI8U3FO Content-Disposition: attachment; filename="firqreader.c" Content-Transfer-Encoding: 7Bit Content-Type: text/x-csrc; charset="UTF-8"; name="firqreader.c" #include #include #include #include #include #include #include #include #include #include #include #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>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, ¶ms); pthread_create(&tid,&rtattr,rtthread,NULL); /* param.sched_priority=98; if(sched_setscheduler(0,SCHED_FIFO,¶m) == -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; } --nextPart2012892.YpTzI8U3FO Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline -- ptxdist mailing list ptxdist@pengutronix.de --nextPart2012892.YpTzI8U3FO--