All of lore.kernel.org
 help / color / mirror / Atom feed
* 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 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

* 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

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.