* Problem with interrupt handler @ 2010-01-25 17:16 Julian Fuchs 2010-01-25 19:31 ` Uwe Kleine-König 2010-01-25 19:35 ` Thomas Gleixner 0 siblings, 2 replies; 5+ messages in thread From: Julian Fuchs @ 2010-01-25 17:16 UTC (permalink / raw) To: linux-rt-users Hello, being aware of the risk to bother some people here I would nevertheless really appreciate your help with the following issue: Is there any difference in the request_irq() function call in comparison to the one in the normal kernel? I'm trying to run request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED | IRQF_NODELAY, MODULE_IDENT, &stage) on 2.6.31.6-rt19 but it doesn't call interrupt_handler() when an interrupt is received. In the plain kernel 2.6.31 it works with this call: request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED, MODULE_IDENT, &stage) Do you have hints to literature / tutorials / code I should look at? I would really appreciate any kind of help, thanks, Julian ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Problem with interrupt handler 2010-01-25 17:16 Problem with interrupt handler Julian Fuchs @ 2010-01-25 19:31 ` Uwe Kleine-König 2010-01-25 22:41 ` Julian Fuchs 2010-01-25 19:35 ` Thomas Gleixner 1 sibling, 1 reply; 5+ messages in thread From: Uwe Kleine-König @ 2010-01-25 19:31 UTC (permalink / raw) To: Julian Fuchs; +Cc: linux-rt-users On Mon, Jan 25, 2010 at 06:16:08PM +0100, Julian Fuchs wrote: > being aware of the risk to bother some people here I would > nevertheless really appreciate your help with the following issue: > > Is there any difference in the request_irq() function call in > comparison to the one in the normal kernel? > > I'm trying to run > > request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED | > IRQF_NODELAY, MODULE_IDENT, &stage) > > on 2.6.31.6-rt19 but it doesn't call interrupt_handler() when an > interrupt is received. > > In the plain kernel 2.6.31 it works with this call: > > request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED, > MODULE_IDENT, &stage) Did you try with IRQF_NODELAY on vanilla and without it in rt? Are you sure the irq fires in rt? Does your interrupt appear in /proc/interrupts? What platform are you working on? Do you can send the code of a minimal example? Best regards Uwe -- Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | http://www.pengutronix.de/ | -- To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Problem with interrupt handler 2010-01-25 19:31 ` Uwe Kleine-König @ 2010-01-25 22:41 ` Julian Fuchs 2010-01-26 11:00 ` Uwe Kleine-König 0 siblings, 1 reply; 5+ messages in thread From: Julian Fuchs @ 2010-01-25 22:41 UTC (permalink / raw) To: Uwe Kleine-König; +Cc: linux-rt-users Hello, thank you very much for your answer. Am 25. Januar 2010 20:31 schrieb Uwe Kleine-König <u.kleine-koenig@pengutronix.de>: > On Mon, Jan 25, 2010 at 06:16:08PM +0100, Julian Fuchs wrote: (...) > Did you try with IRQF_NODELAY on vanilla and without it in rt? I tried it with IRQF_NODELAY in rt and without IRQF_NODELAY on vanilla (vanilla won't compile with IRQF_NODELAY AFAIR). > Are you sure the irq fires in rt? It fires in the normal kernel (i.e. the hardware is working). How can I determine whether the interrupt fires in rt? > Does your interrupt appear in /proc/interrupts? Yes, it appears there (and the name of the module is listed correctly in the same line). On vanilla, the counter in /proc/interrupts increases, on rt, it doesn't. It seems that the interrupt just doesn't fire... is there any kind of "magic" I can do on rt to "enable" the interrupt? It seems disabled :-( > What platform are you working on? I'm working on a Intel Celeron 1,8 GHz board (x86) with Ubuntu Linux 9.10 as a distro. > Do you can send the code of a minimal example? Sure. Below you find the code of a minimal example for a rs232 interface. If you have any suggestions for a smaller example, please tell me and will create it (I just don't know how to create the interrupt otherwise). Thanks a lot for your help, Julian ----- #include <linux/module.h> #include <linux/kernel.h> #include <linux/mm.h> #include <asm/uaccess.h> #include <linux/sched.h> #include <linux/ioport.h> #include <asm/io.h> #include <linux/proc_fs.h> #include <linux/inet.h> #include <linux/net.h> #include <net/tcp.h> #include <net/ip.h> #include <net/protocol.h> /* --- DEFITIONS AND SETTINGS --- */ // Module information MODULE_AUTHOR("Somebody"); MODULE_DESCRIPTION("some serial interface driver"); MODULE_LICENSE("GPL"); #define MODULE_IDENT "foobar" #define VERSION_STRING "foobar v0.1\n" // Configurable parameters int base_port = 0xcf00; const int port_range = 8; int irq = 16; int irq_counter = 0; module_param(base_port, int, 0644); MODULE_PARM_DESC(base_port, "The base port address of the serial interface"); module_param(irq, int, 0644); MODULE_PARM_DESC(irq, "IRQ of the serial interface"); // Serial port communication // registers #define IER 1 // interrupt enable register #define FCR 2 // FIFO control register (write) / Interrupt Identification Register (read) #define LCR 3 // line control register // serial port settings #define PARITY_NO 0x0 #define STOPBIT_1 0 #define CS_8 0x3 #define MAX_BAUDRATE 921600 #define DIVISOR_ACCESS 0x80 // interrupt identification and enabling #define IER_DATA_AVAILABLE 0x1 #define IER_LS_CHANGE 0x4 // Global control variables int stage = 0; /* --- SERIAL PORT CONFIGURATION INTERFACE --- */ void set_serial_options(void); void set_serial_options(void) { unsigned int divisor; unsigned char parity, stopbit, cs, status; stopbit = STOPBIT_1; parity = PARITY_NO; cs = CS_8; status = parity | stopbit | cs | DIVISOR_ACCESS; outb(status, base_port+LCR); divisor = 24; outb(divisor & 0x00ff, base_port); outb(divisor & 0xff00, base_port+1); // reset divisor access bit outb(status &~ DIVISOR_ACCESS, base_port+LCR); } irqreturn_t interrupt_handler(int myirq, void *dev_id) { unsigned char iir_byte, bitmask; iir_byte = inb(base_port + FCR); bitmask = 1; if ( (iir_byte & bitmask) == 1) { // interrupt is not for this module return IRQ_NONE; } // interrupt is for this module unsigned char data_byte; data_byte = inb(base_port); irq_counter++; return IRQ_HANDLED; } void cleanup_module(void) { // I/O ports reserved if (stage >= 2) { release_region(base_port, port_range); printk(KERN_INFO "%s: releasing I/O ports\n", MODULE_IDENT); } // IRQ reserved if (stage >= 1) { // because of shared irq, &stage is given, otherwise NULL will do, too free_irq(irq, &stage); // disable interrupts from the card outb(0, base_port + IER); printk(KERN_INFO "%s: freeing irq %i\n", MODULE_IDENT, irq); } printk(KERN_INFO "%s: module unloaded\n", MODULE_IDENT); printk(KERN_ERR "%d irq_counter\n", irq_counter); } /* Setup all operations - called by kernel when module is loaded */ int init_module(void) { int err = 0; printk(KERN_INFO VERSION_STRING); // Stage 1. Request IRQ using shared interrupts // dev_id can't be NULL since the kernel needs to label the different ISRs // stage is just as a pointer to our address space, any other address will do, too. if ((err = request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED | IRQF_NODELAY, MODULE_IDENT, &stage)) < 0) return err; stage++; // Stage 2. Request access to I/O ports if ((err = check_region(base_port, port_range)) < 0) { cleanup_module(); return err; } request_region(base_port, port_range, MODULE_IDENT); stage++; printk(KERN_INFO "Using serial port at %x, IRQ %i\n", base_port, irq); // Configure serial port set_serial_options(); // disable FIFO outb(0, base_port+FCR); // enable interrupts if data available or break signal received outb(IER_DATA_AVAILABLE | IER_LS_CHANGE, base_port+IER); printk(KERN_ERR "INIT MODULE DONE!\n"); return 0; } -- To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Problem with interrupt handler 2010-01-25 22:41 ` Julian Fuchs @ 2010-01-26 11:00 ` Uwe Kleine-König 0 siblings, 0 replies; 5+ messages in thread From: Uwe Kleine-König @ 2010-01-26 11:00 UTC (permalink / raw) To: Julian Fuchs; +Cc: linux-rt-users Hello Julian, On Mon, Jan 25, 2010 at 11:41:46PM +0100, Julian Fuchs wrote: > thank you very much for your answer. > > Am 25. Januar 2010 20:31 schrieb Uwe Kleine-König > <u.kleine-koenig@pengutronix.de>: > > On Mon, Jan 25, 2010 at 06:16:08PM +0100, Julian Fuchs wrote: > (...) > > Did you try with IRQF_NODELAY on vanilla and without it in rt? > > I tried it with IRQF_NODELAY in rt and without IRQF_NODELAY on vanilla > (vanilla won't compile with IRQF_NODELAY AFAIR). > > > Are you sure the irq fires in rt? > > It fires in the normal kernel (i.e. the hardware is working). How can > I determine whether the interrupt fires in rt? > > > Does your interrupt appear in /proc/interrupts? > > Yes, it appears there (and the name of the module is listed correctly > in the same line). > > On vanilla, the counter in /proc/interrupts increases, on rt, it > doesn't. It seems that the interrupt just doesn't fire... is there any > kind of "magic" I can do on rt to "enable" the interrupt? It seems > disabled :-( > > > What platform are you working on? > > I'm working on a Intel Celeron 1,8 GHz board (x86) with Ubuntu Linux > 9.10 as a distro. > > > Do you can send the code of a minimal example? > > Sure. Below you find the code of a minimal example for a rs232 > interface. If you have any suggestions for a smaller example, please > tell me and will create it (I just don't know how to create the > interrupt otherwise). > > Thanks a lot for your help, > > Julian > > ----- > #include <linux/module.h> > #include <linux/kernel.h> > #include <linux/mm.h> > #include <asm/uaccess.h> > #include <linux/sched.h> > #include <linux/ioport.h> > #include <asm/io.h> > #include <linux/proc_fs.h> > #include <linux/inet.h> > #include <linux/net.h> > #include <net/tcp.h> > #include <net/ip.h> > #include <net/protocol.h> > > > /* --- DEFITIONS AND SETTINGS --- */ > > // Module information > MODULE_AUTHOR("Somebody"); > MODULE_DESCRIPTION("some serial interface driver"); > MODULE_LICENSE("GPL"); > #define MODULE_IDENT "foobar" > #define VERSION_STRING "foobar v0.1\n" > > // Configurable parameters > int base_port = 0xcf00; > const int port_range = 8; > int irq = 16; > > int irq_counter = 0; > > module_param(base_port, int, 0644); > MODULE_PARM_DESC(base_port, "The base port address of the serial interface"); > module_param(irq, int, 0644); > MODULE_PARM_DESC(irq, "IRQ of the serial interface"); > > > // Serial port communication > // registers > #define IER 1 // interrupt enable register > #define FCR 2 // FIFO control register (write) / Interrupt > Identification Register (read) > #define LCR 3 // line control register > > // serial port settings > #define PARITY_NO 0x0 > #define STOPBIT_1 0 > #define CS_8 0x3 > #define MAX_BAUDRATE 921600 > > #define DIVISOR_ACCESS 0x80 > > // interrupt identification and enabling > #define IER_DATA_AVAILABLE 0x1 > #define IER_LS_CHANGE 0x4 > > // Global control variables > int stage = 0; > > /* --- SERIAL PORT CONFIGURATION INTERFACE --- */ > > void set_serial_options(void); > > void set_serial_options(void) { > unsigned int divisor; > unsigned char parity, stopbit, cs, status; > > stopbit = STOPBIT_1; > parity = PARITY_NO; > cs = CS_8; > > status = parity | stopbit | cs | DIVISOR_ACCESS; > outb(status, base_port+LCR); > divisor = 24; > outb(divisor & 0x00ff, base_port); > outb(divisor & 0xff00, base_port+1); > > // reset divisor access bit > outb(status &~ DIVISOR_ACCESS, base_port+LCR); > } > > > irqreturn_t interrupt_handler(int myirq, void *dev_id) { > > unsigned char iir_byte, bitmask; > iir_byte = inb(base_port + FCR); > bitmask = 1; > if ( (iir_byte & bitmask) == 1) { > // interrupt is not for this module > return IRQ_NONE; > } > // interrupt is for this module > unsigned char data_byte; > data_byte = inb(base_port); > > irq_counter++; > > return IRQ_HANDLED; > } > > > void cleanup_module(void) { > // I/O ports reserved > if (stage >= 2) { > release_region(base_port, port_range); > printk(KERN_INFO "%s: releasing I/O ports\n", MODULE_IDENT); > } > // IRQ reserved > if (stage >= 1) { > // because of shared irq, &stage is given, otherwise NULL will do, too > free_irq(irq, &stage); > // disable interrupts from the card > outb(0, base_port + IER); > > printk(KERN_INFO "%s: freeing irq %i\n", MODULE_IDENT, irq); > } > printk(KERN_INFO "%s: module unloaded\n", MODULE_IDENT); > > printk(KERN_ERR "%d irq_counter\n", irq_counter); > } > > /* Setup all operations - called by kernel when module is loaded */ > int init_module(void) { > > int err = 0; > > printk(KERN_INFO VERSION_STRING); > > // Stage 1. Request IRQ using shared interrupts > // dev_id can't be NULL since the kernel needs to label the different ISRs > // stage is just as a pointer to our address space, any other address > will do, too. > if ((err = request_irq(irq, interrupt_handler, IRQF_SHARED | > IRQF_DISABLED | IRQF_NODELAY, MODULE_IDENT, &stage)) < 0) return err; Do you really need to share the irq, can you try without sharing? > stage++; > > // Stage 2. Request access to I/O ports > if ((err = check_region(base_port, port_range)) < 0) { > cleanup_module(); > return err; > } > request_region(base_port, port_range, MODULE_IDENT); don't use check_region, but the return value of request_region to check for errors. You're approach is racy. > stage++; > > printk(KERN_INFO "Using serial port at %x, IRQ %i\n", base_port, irq); > > // Configure serial port > set_serial_options(); > > // disable FIFO > outb(0, base_port+FCR); > > // enable interrupts if data available or break signal received > outb(IER_DATA_AVAILABLE | IER_LS_CHANGE, base_port+IER); > > printk(KERN_ERR "INIT MODULE DONE!\n"); > > return 0; > } I assume you don't have another driver loaded that might look after your device? Does it autoload, so you have to unload it before you start with your module? Do you need your module, the existing drivers don't provide what you need? Other than that I don't have an idea. Best regards Uwe -- Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | http://www.pengutronix.de/ | -- To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Problem with interrupt handler 2010-01-25 17:16 Problem with interrupt handler Julian Fuchs 2010-01-25 19:31 ` Uwe Kleine-König @ 2010-01-25 19:35 ` Thomas Gleixner 1 sibling, 0 replies; 5+ messages in thread From: Thomas Gleixner @ 2010-01-25 19:35 UTC (permalink / raw) To: Julian Fuchs; +Cc: linux-rt-users On Mon, 25 Jan 2010, Julian Fuchs wrote: > Hello, > > being aware of the risk to bother some people here I would > nevertheless really appreciate your help with the following issue: > > Is there any difference in the request_irq() function call in > comparison to the one in the normal kernel? > > I'm trying to run > > request_irq(irq, interrupt_handler, IRQF_SHARED | IRQF_DISABLED | > IRQF_NODELAY, MODULE_IDENT, &stage) Does the function return 0 ? Thanks, tglx ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-01-26 11:00 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-01-25 17:16 Problem with interrupt handler Julian Fuchs 2010-01-25 19:31 ` Uwe Kleine-König 2010-01-25 22:41 ` Julian Fuchs 2010-01-26 11:00 ` Uwe Kleine-König 2010-01-25 19:35 ` Thomas Gleixner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox