P.S. Если указываете свою железку (HLV800-256AV) - указывайте и URL производителя для этой железки.
Посмотрите внимательнее что там за контроллер прерываний стоит.
К сожалению в мануале на железку не описано какой контроллер используется. Хотя предполагаю что он - I8259. Об этом говорит proc/interrupts.
Код: Выделить всё
[root@DSC_DKLinux> cat /proc/interrupts
CPU0
0: 342679 XT-PIC-XT timer
1: 8 XT-PIC-XT i8042
2: 0 XT-PIC-XT cascade
5: 901625 XT-PIC-XT HeliosTimer
6: 0 XT-PIC-XT ehci_hcd:usb1
9: 18581 XT-PIC-XT ehci_hcd:usb2, ohci_hcd:usb3, eth0
12: 121 XT-PIC-XT i8042
14: 68533 XT-PIC-XT ide0
15: 0 XT-PIC-XT ohci_hcd:usb4
NMI: 0
ERR: 0
Процессор Vortex86DX архитектура x86. Те система не многопроцессорная, если я правильно понимаю аббревиатуру SMP.
http://docs2.diamondsystems.com/files/b ... Manual.pdf
http://docs2.diamondsystems.com/products/helios
Картина будет существенным образом зависеть от того, как запрограммирована реакция у вас контроллера прерываний: а). по уровню, б). по фронту.
Честно говоря не заморачивался как запрограммирован контроллер прерываний в линуксе по уровню или по фронту. Ведь прерывания доходят до моего обработчика :
В заголовочном файле interrupt.h конечно есть флаги по заданию реакции, однако я их не использовал и при этом все работает.
Код: Выделить всё
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010
Задавал только флаги IRQF_TIMER и IRQF_DISABLED. И чесно говоря разницы не заметил.
result = request_irq(irq, &my_interrupt, IRQF_DISABLED /*IRQF_TIMER*/, "HeliosTimer", &my_dev_id);
1. Ни при каких условиях.
(Разве что на время обработки "нижней половины" прерывания, когда прерывания по этой линии IRQ запрещены)
С обработкой "нижней половины" пока не разобрался поэтому и такой простой обработчик прерывания.
Vladmir писал(а):При увеличении частоты таймера скажем до 40КГц (25 микросекунд), обработчик прерываний выполняется какое-то время и после чего перестает вызываться (cat /proc/interrupts счетчик событий останавливается), при этом другие функции модуля ядра работают (IOCTL READ итп). После этого обработчик прерываний как-будто бы вообще перестает отрабатывать.
Такого быть не может. Поэтому ищите какое-то другое объяснение наблюдаемому.
Однако есть. Объяснение найти пока не получается.
Выкладываю полный текст модуля и тестовой программы
Код: Выделить всё
/*
* HKM - Helios Kernel Module
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fs.h> /* file_operations */
#include <asm/io.h>
#include <asm/uaccess.h> /* copy_to_user */
#include "hkm.h"
static int irq = 5; /* Interrupt number IRQ */
static int my_dev_id =0; /* Unique ID when registering interrupts */
static unsigned int irq_counter = 0; /* Event counter interrupts */
static int hkm_major = 251;
#define BAHelios 0x280 /* Base address of the board Helios in the system */
/* Interrupt handler */
static irqreturn_t my_interrupt( int irq, void *dev_id )
{
irq_counter++;
outb(0x04,BAHelios); //Clear the interrupt on the board Helios
return IRQ_HANDLED;
}
/*
* hkm_open() - Handle open(/dev/hkm)
*/
static int hkm_open(struct inode *node, struct file *filep)
{
// printk("hkm: hkm_open() \n");
return 0;
}
/*
* hkm_ioctl() - Handle ioctl(/dev/hkm)
*/
static int hkm_ioctl(struct inode *node, struct file *filep, unsigned int cmd,
unsigned long arg)
{
int rc;
if ( cmd == IOCTL_DSCUDKP_CONF )
{
rc = copy_to_user((void *)arg, (void *)&irq_counter, sizeof(unsigned int/*irq_counter*/));
if ( rc ) {
printk("hkm: hkm_ioctl(): IOCTL_DSCUDKP_CONF copy_to_user() failed with rc=%d\n", rc);
return -EFAULT;
}
}
return 0;
}
/*
* Initialize file_operations structure used to attach to events on /dev/hkm
* such as open/close.
*/
static struct file_operations hkm_fops = {
open: hkm_open,
// release: hkm_release,
ioctl: hkm_ioctl,
// read: hkm_read,
};
/* Initialize (load) the module */
static int __init my_init( void )
{
int rc;
rc = register_chrdev(hkm_major, "hkm", &hkm_fops);
if (rc<0)
{
printk(KERN_INFO "short: can't get major number \n");
return rc;
}
irq_counter = 0;
outb(0,BAHelios+4); //Read/Write Interrupt / Counter Control
int result;
result = request_irq(irq, &my_interrupt, IRQF_DISABLED /*IRQF_TIMER*/, "HeliosTimer", &my_dev_id);
if (result < 0)
{
printk(KERN_ALERT "Error to request IRQ%d : %u\n", irq, result);
return -1;
}
// Start interrupt from borad
unsigned char temp;
temp = inb(BAHelios+11);
outb(temp & 0x7F,BAHelios+11); //Bit is cleared DIOCTR=0
//printk( KERN_INFO "hex BAHelios+11= %x \n", temp);
//Load divider in counter 1 = 10000 for 1KGH
// outb(0x10 ,BAHelios+12); //Value (divider) for load
// outb(0x27 ,BAHelios+13);
//Load divider in counter 1 = 1000 for 10KGH 100mkc(working with IRQF_DISABLED (5-tiks timer printf test.c))
// outb(0xE8 ,BAHelios+12); //Value (divider) for load
// outb(0x03 ,BAHelios+13);
//Load divider in counter 1 = 625 for 16KGH 62mkc(working with IRQF_DISABLED (3-tiks timer printf test.c))
// outb(0x71 ,BAHelios+12); //Value (divider) for load
// outb(0x02 ,BAHelios+13);
//Load divider in counter 1 = 500 for 20KGH 50mkc(working with IRQF_DISABLED (2-tiks timer printf test.c 25mkc))
// outb(0xF4 ,BAHelios+12); //Value (divider) for load
// outb(0x01 ,BAHelios+13);
//Load divider in counter 1 = 400 for 25KGH 40mkc(not working)
// outb(0x90 ,BAHelios+12); //Value (divider) for load
// outb(0x01 ,BAHelios+13);
//Load divider in counter 1 = 250 for 40KGH 25mkc
outb(0xFA ,BAHelios+12); //Value (divider) for load
outb(0x00 ,BAHelios+13);
//Load divider in counter 1 = 200 for 50KGH 20mkc
// outb(0xC8 ,BAHelios+12); //Value (divider) for load
// outb(0x00 ,BAHelios+13);
//Load Counter 1
outb(0x82 ,BAHelios+15);
outb(0x04 ,BAHelios+4); //Frequency 10Mgz and Interrupt handling Timer 1
outb(0x84 ,BAHelios+15); //Enable count for the timer
printk( KERN_INFO "Successfully loading ISR handler on IRQ %u\n", irq );
return 0;
}
/* Finalizing (unload) module */
static void __exit my_exit( void )
{
unregister_chrdev(hkm_major, "hkm");
outb(0x88 ,BAHelios+15); //Disable count for the timer
free_irq( irq, &my_dev_id );
printk( KERN_INFO "Successfully unloading, irq_counter = %u\n", irq_counter);
}
module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE("GPL");
И тестовая прога которая которая получает к себе значение счетчика
Код: Выделить всё
/*
* test.c - test module KHM
*
*/
#include <stdio.h>
#include "hkm.h"
int main(int argc,char *argv[])
{
unsigned int kernelclock;
int fd;
fd = open("/dev/hkm", "r");
if (fd<0){
printf("Error to open\n");
};
while (1){
if (ioctl(fd, IOCTL_DSCUDKP_CONF, &kernelclock)<0){printf ("Error \n");}
printf ("Cur Clock Timer from driver %u\n",kernelclock);
}
close(fd);
return(0);
}