Re: Problem with interrupt handler

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxx>:
> > 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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux