⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupt_latency_mediaengine.c

📁 《嵌入式Linux-硬件
💻 C
字号:
/* * interrupt_latency_mediaengine v1.1 12/10/02 * www.embeddedlinuxinterfacing.com * * The original location of this code is * http://www.embeddedlinuxinterfacing.com/chapters/11/ * * Copyright (C) 2001 by Craig Hollabaugh * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* * interrupt_latency_mediaengine.c is based on procfs_example.c by Erik Mouw. * For more information, please see, The Linux Kernel Procfs Guide, Erik Mouw * http://kernelnewbies.org/documents/kdoc/procfs-guide/lkprocfsguide.html *//*arm-linux-gcc -O2 -D__KERNEL__ -DMODULE -I/usr/src/arm-linux/include -c interrupt_latency_mediaengine.c -o /tftpboot/arm-rootfs/tmp/interrupt_latency_mediaengine.o*//* interrupt_latency_mediaengine.c module * This module measures instantanous interrupt latency of the MediaEngine * using GPIO01. Configure the GRER for GPIO01 rising edge interrupt * generation. Setting GPIO01 as an output then setting GPIO01 causes a * rising edge that generates the interrupt. GRER is set by ARM kernel * code, therefore just setting the register itself is not enough. Use * the set_GPIO_IRQ_edge  ARM-only function. See kernel source for more info. * * After module insertion, reading /proc/interrupt_latency will assert GPIO01 * generating the interrupt. The interrupt handler will deassert this signal. * View on scope. An interrupt counter is included to help debug noisy a * interrupt line. *//* v1.1  * a. Moved GPIO01 as output after set_GPIO_IRQ_edge, set_GPIO_IRQ_edge clears the gpdr bit in 2.4.17 * b. Moved the GPIO01 as output below where the original gpdr setting is actually read */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <asm/io.h>#define MODULE_VERSION "1.0"#define MODULE_NAME "interrupt_latency_mediaengine"/* see 9.1.1.1 Intel StrongARM SA-1110 Microprocessor Developer's Manual *//* these are also defined in arch SA-1100.h but differently*/#define GPIO         0x90040000 /* GPIO registers base address */#define GPLR_OFFSET  0x00#define GPDR_OFFSET  0x04#define GPSR_OFFSET  0x08#define GPCR_OFFSET  0x0C#define GAFR_OFFSET  0x1C#define GRER_OFFSET  0x10#define GFER_OFFSET  0x14#define GEDR_OFFSET  0x18#define GPIOLEN      0x20#define GPIO01       0x00000002#define IC           0x90050000 /* Interrupt controller regstr base address */#define ICIP_OFFSET  0x00#define ICMR_OFFSET  0x04#define ICLR_OFFSET  0x08#define ICFP_OFFSET  0x10#define ICLEN        0x20static void *ic_base, *gpio_base;unsigned long int gpdr, gafr, grer;int interruptcount = 0;struct timeval tv1, tv2;#define INTERRUPT 1static struct proc_dir_entry *interrupt_latency_file;/* * function interrupt_interrupt_latency * This function is the interrupt handler for interrupt 1. It sets the tv2 * structure using do_gettimeofday. It then clears GPIO01. */void interrupt_interrupt_latency(int irq, void *dev_id, struct pt_regs *regs){  do_gettimeofday(&tv2);  writel(GPIO01, gpio_base + GPCR_OFFSET); /* deassert the interrupt signal */  interruptcount++;}/* * function proc_read_interrupt_latency * The kernel executes this function when a read operation occurs on * /proc/interrupt_latency. This function sets the tv1 structure. It asserts * GPIO01 which should immediately cause interrupt 1 to occur. The handler * records tv2 and deasserts GPIO01. This function returns the time * differential between tv2 and tv1. */static int proc_read_interrupt_latency(char *page, char **start, off_t off,                                       int count, int *eof, void *data){  int len;  do_gettimeofday(&tv1);  writel(GPIO01, gpio_base + GPSR_OFFSET); /* assert the interrupt signal */ len = sprintf(page,"Start %9i.%06i\nFinish %9i.%06i\nLatency %6i\nCount%i\n",                      (int) tv1.tv_sec, (int) tv1.tv_usec,                      (int) tv2.tv_sec, (int) tv2.tv_usec,                      (int) (tv2.tv_usec - tv1.tv_usec),                      interruptcount);  return len;}/* * function init_interrupt_latency * This function creates the /proc directory entry interrupt_latency. It * requests interrupt 1 from Linux then configures the interrupt controller. */static int __init init_interrupt_latency(void){  unsigned long r;  int rv = 0;  interrupt_latency_file = create_proc_entry("interrupt_latency", 0444, NULL);  if(interrupt_latency_file == NULL) {    return -ENOMEM;  }  interrupt_latency_file->data = NULL;  interrupt_latency_file->read_proc = &proc_read_interrupt_latency;  interrupt_latency_file->write_proc = NULL;  interrupt_latency_file->owner = THIS_MODULE;  ic_base = ioremap_nocache(IC,ICLEN);  printk("ic_base       = 0x%08X\n",ic_base);  /* request interrupt from linux */  rv = request_irq(INTERRUPT, interrupt_interrupt_latency, 0,                   "interrupt_latency",NULL);  if ( rv ) {    printk("Can't get interrupt %d\n", INTERRUPT);    goto no_interrupt_latency;  }  /* print out interrupt controller status bits */  r = readl(ic_base + ICIP_OFFSET);  printk("ICIP          = 0x%08X\n",r);  r = readl(ic_base + ICMR_OFFSET);  printk("ICMR          = 0x%08X\n",r); /* bit is set here for INT1 */  r = readl(ic_base + ICLR_OFFSET);  printk("ICLR          = 0x%08X\n",r);  r = readl(ic_base + ICFP_OFFSET);  printk("ICFP          = 0x%08X\n",r);  /* get GPIO base for register changing */  gpio_base = ioremap_nocache(GPIO,GPIOLEN);  printk("\ngpio_base     = 0x%08X\n",gpio_base);  gpdr = readl(gpio_base + GPDR_OFFSET); /* preserve the gpdr bits */  printk("GPDR          = 0x%08X\n",gpdr);  gafr = readl(gpio_base + GAFR_OFFSET); /* preserve the gafr bits */  printk("GAFR          = 0x%08X\n",gafr);  r = readl(gpio_base + GPLR_OFFSET);  printk("GPLR          = 0x%08X\n",r);  grer = readl(gpio_base + GRER_OFFSET); /* preserve the grer bits */  printk("GRER          = 0x%08X\n",grer);/* use ARM-only Linux function requesting edge int */  set_GPIO_IRQ_edge(GPIO01, GPIO_RISING_EDGE);  printk("set_GPIO_IRQ_edge\n");/* set GPIO01 to have rising edge int */  writel(grer | GPIO01, gpio_base + GRER_OFFSET);  /* configuring GPIO01 as output *//* set GPIO01 as output */  writel(gpdr |  GPIO01, gpio_base + GPDR_OFFSET);/* set GPIO01 with no alt function */  writel(gafr & ~GPIO01, gpio_base + GAFR_OFFSET);  writel(GPIO01             , gpio_base + GPCR_OFFSET);  /* clear GPIO01 */   r = readl(gpio_base + GPDR_OFFSET);   printk("GPDR          = 0x%08X\n",r);  r = readl(gpio_base + GAFR_OFFSET);   printk("GAFR          = 0x%08X\n",r);  r = readl(gpio_base + GRER_OFFSET);  printk("GRER          = 0x%08X\n",r);  r = readl(gpio_base + GFER_OFFSET);  printk("GFER          = 0x%08X\n",r);  r = readl(gpio_base + GEDR_OFFSET);  printk("GEDR          = 0x%08X\n",r);  /* everything initialized */  printk(KERN_INFO "%s %s initialized\n",MODULE_NAME, MODULE_VERSION);  return 0;no_interrupt_latency:  remove_proc_entry("interrupt_latency", NULL);}/* * function cleanup_interrupt_latency * This function frees interrupt 1,  restores registers, then removes the * /proc directory entry interrupt_latency. */static void __exit cleanup_interrupt_latency(void){  free_irq(INTERRUPT,NULL); /* free the interrupt */  writel(gpdr, gpio_base + GPDR_OFFSET);  /* restore gpdr */  writel(gafr, gpio_base + GAFR_OFFSET);  /* restore gafr */  writel(grer, gpio_base + GRER_OFFSET);  /* restore grer */  iounmap(ic_base);  iounmap(gpio_base);  remove_proc_entry("interrupt_latency", NULL);  printk(KERN_INFO "%s %s removed\n", MODULE_NAME, MODULE_VERSION);}module_init(init_interrupt_latency);module_exit(cleanup_interrupt_latency);MODULE_AUTHOR("Craig Hollabaugh");MODULE_DESCRIPTION("interrupt_latency proc module");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -