如何映射中断ID和ISR?

时间:2016-01-20 17:35:03

标签: linux-kernel operating-system linux-device-driver kernel-module

我正在从CS.USFCA学习实验4,它为虚拟NIC生成模拟中断。 课程页面: http://cs.usfca.edu/~cruse/cs686s08/

该程序将创建一个模拟的NIC接口,用户可以通过cat proc来手动向NIC发出中断。

步骤:

  1. cat / proc / interrupt 选择正确的IRQ,然后选择IRQ#18
  2. 然后我打印出IOAPIC的内容。条目#18 bit0-7是55,所以我将IntID设置为55。

  3. 接下来,我安装模块,并使用 ifconfig 启动eth3。 IRQ是18,这是正确的。

  4. 在通过 cat / proc / netframe 模拟中断的同时,内核日志显示 [18828.842375] do_IRQ:1.85没有矢量的irq处理程序(irq -1)

  5. 我知道Linux自己管理0-255个中断向量,IOAPIC中的24个条目决定IO设备的中断如何传送到CPU(英特尔)。
    在我的情况下,似乎我触发了错误的中断。所以CPU无法找到正确的irq处理程序。

    但在我的情况下,中断如何映射到相应的IRQ?

    enter image description here

    enter image description here

    enter image description here

    我的代码

    #include <linux/module.h>   // for init_module() 
    #include <linux/etherdevice.h>  // for alloc_etherdev()
    #include <linux/proc_fs.h>  // for create_proc_info_entry() 
    #include <linux/interrupt.h>    // for request_irq(), free_irq()
    #include <linux/wait.h>     // for init_wait_queue_head()
    #include <linux/seq_file.h>
    
    #define irqID       0x12    // temporary -- an unused IRQ
    #define intID       0x55    // temporary -- IOAPIC mapped  
    
    typedef struct  {
        struct tasklet_struct   my_rxtasklet;
        wait_queue_head_t   my_waitqueue;
        spinlock_t      my_lock;
    } MY_DRIVERDATA;
    
    
    int my_open( struct net_device * );
    int my_stop( struct net_device * );
    int my_hard_start_xmit( struct sk_buff *, struct net_device * );
    irqreturn_t my_isr( int, void * );
    void my_rx_handler( unsigned long );
    int my_get_info( char *, char **, off_t, int );
    
    char modname[] = "netframe";
    
    static const struct net_device_ops mynetdev_ops={
        .ndo_open=my_open,
        .ndo_stop       = my_stop,
        .ndo_start_xmit = my_hard_start_xmit,
    }; 
    
    struct net_device  *netdev;
    
    int my_get_info( char *buf, char **start, off_t off, int count )
    {
        int len = 0;
        int i;
        *start = buf;
        if ( off == 0 )
        {
            len += sprintf( buf+len, "simulating an interrupt " );
            len += sprintf( buf+len, "by \'%s\' \n", netdev->name  );
            off += len;
        } 
        else
        {
            asm(" int %0 " : : "i" (intID) );
        }
    
        return  len;
    }  
    
    static int my_seq_open(struct inode *inode,struct file *file){
        printk(KERN_ALERT "DEBUG: Enter %s\n",__FUNCTION__);
        return single_open(file, &seq_proc_show,NULL);
    }
    
    struct file_operations fops = {
        .read=my_get_info,
    };
    
    static int __init my_init( void )
    { 
        printk( "<1>\nInstalling \'%s\' module\n", modname );
    
        if(!proc_create(modname,0666,NULL,&fops)){
            printk(KERN_INFO "ERROR! proc_create\n");
            remove_proc_entry(modname,NULL);
            return -1;
        }
        netdev = alloc_etherdev( sizeof( MY_DRIVERDATA ) );
        if ( !netdev ) return -ENOMEM;
        netdev->irq     = irqID;
        netdev->netdev_ops=&mynetdev_ops;
    
        return  register_netdev( netdev );  
    } 
    
    static void __exit my_exit(void )
    {
        unregister_netdev( netdev );
        free_netdev( netdev );
        remove_proc_entry( modname, NULL );
        printk( "<1>Removing \'%s\' module\n", modname );
    }
    
    int my_open( struct net_device *dev ) 
    {  
        MY_DRIVERDATA   *priv = netdev_priv(dev);
        unsigned long   devaddr = (unsigned long)dev;
    
        printk( "opening the \'%s\' interface \n", dev->name );
    
        spin_lock_init( &priv->my_lock );
        init_waitqueue_head( &priv->my_waitqueue );
        tasklet_init( &priv->my_rxtasklet, my_rx_handler, devaddr );
    
        if ( request_irq( dev->irq, my_isr, IRQF_SHARED, dev->name, dev ) < 0) return -EBUSY;
    
        netif_start_queue( dev );
        return 0; 
    }
    
    int my_stop( struct net_device *dev ) 
    { 
        MY_DRIVERDATA   *priv = netdev_priv(dev);
    
        printk( "stopping the \'%s\' interface \n", dev->name );
    
        free_irq( dev->irq, dev );
    
        tasklet_kill( &priv->my_rxtasklet );
        netif_stop_queue( dev );
        return 0; 
    }
    
    int my_hard_start_xmit( struct sk_buff *skb, struct net_device *dev )
    { 
        MY_DRIVERDATA   *priv = netdev_priv(dev);
    
        printk( "starting transmit on the \'%s\' interface \n", dev->name );
    
        dev->trans_start = jiffies;
        dev->stats.tx_packets += 1;
        dev->stats.tx_bytes += skb->len;
    
        wait_event_interruptible( priv->my_waitqueue, 1 );
    
        dev_kfree_skb( skb );
        return 0;
    }
    
    irqreturn_t my_isr( int irq, void *data )
    { 
        struct net_device   *dev = (struct net_device*)data;
        MY_DRIVERDATA   *priv = netdev_priv(dev);
        tasklet_schedule( &priv->my_rxtasklet );
        wake_up_interruptible( &priv->my_waitqueue );
        return  IRQ_HANDLED;
    } 
    
    void my_rx_handler( unsigned long data )
    {
        struct net_device   *dev = (struct net_device *)data;
        struct sk_buff      *skb;
        int         rxbytes = 60;
    
        skb = dev_alloc_skb( rxbytes + 2 );
        skb->dev = dev;
        skb->protocol = eth_type_trans( skb, dev );
        skb->ip_summed = CHECKSUM_NONE;
        dev->stats.rx_packets += 1;
        dev->stats.rx_bytes += rxbytes;
        netif_rx( skb );
    } 
    
    module_init( my_init );
    module_exit( my_exit );
    MODULE_LICENSE("GPL");
    

0 个答案:

没有答案