• [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)


    目的:

    1. 为我们自己的watchdog写一个驱动

    步骤:

    通过之前的介绍,我们很容易猜想到写我们基于PCI的watchdog驱动,可以分2个步骤。

    1. 探测加载PCI设备

    这部分代码跟我们的设备本身没有任何关系。

    我们通过这部分代码,找到 厂商ID为 0x1af4, 设备ID为0x0101的设备。这个设备是我们用qemu中定义我们的watchdog中指定的。

    #define PCI_VENDOR_ID_REDHAT 0x1af4
    #define PCI_DEVICE_ID_CWD 0x0101

    很自然的可以先到我们需要一个probe的函数来探测PCI设备。 事实确实如此。

    我们通过一个pci_driver定义这部分。

    static struct pci_driver cwd_driver = {
            .name           = ESB_MODULE_NAME,
            .id_table       = cwd_pci_tbl,
            .probe          = cwd_probe,
            .remove         = cwd_remove,
            .shutdown       = cwd_shutdown,
    };

    我们可以直接参考一下其他的PCI设备驱代码来实现这部分代码,比如: drivers/watchdog/i6300esb.c

    代码如下。

    cwd_demo.c

      1 #include <linux/init.h>  //初始换函数 
      2 #include <linux/kernel.h>  //内核头文件 
      3 #include <linux/module.h>  //模块的头文件 
      4 #include <linux/pci.h> 
      5 #include <linux/miscdevice.h> 
      6 #include <linux/types.h> 
      7 #include <linux/fs.h> 
      8 #include <linux/mm.h> 
      9 #include <linux/watchdog.h> 
     10 #include <linux/ioport.h> 
     11 #include <linux/uaccess.h> 
     12 #include <linux/io.h> 
     13  
     14  
     15  
     16 #define ESB_MODULE_NAME "cstl watchdog" 
     17  
     18 /* We only use 1 card for cwd_demo */ 
     19 static int cards_found; 
     20 static struct pci_dev *cwd_pci; 
     21  
     22 MODULE_LICENSE("GPL"); 
     23  
     24 #define CWD_VERSION "0.1" 
     25 #define PCI_VENDOR_ID_REDHAT 0x1af4 
     26 #define PCI_DEVICE_ID_CWD 0x0101 
     27 /* internal variables */ 
     28 static void __iomem *BASEADDR; 
     29  
     30  
     31 /*  
     32  * Data for PCI driver interface  
     33  */  
     34 static DEFINE_PCI_DEVICE_TABLE(cwd_pci_tbl) = {  
     35         { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_CWD), },
     36         { 0, },                 /* End of list */
     37 };
     38 MODULE_DEVICE_TABLE(pci, cwd_pci_tbl);
     39 
     40 
     41 static unsigned char cwd_getdevice(struct pci_dev *pdev)
     42 {
     43         if (pci_enable_device(pdev)) {
     44                 printk(KERN_ERR "failed to enable device
    ");
     45                 goto err_devput;
     46         }
     47 
     48         if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
     49                 printk(KERN_ERR "failed to request region
    ");
     50                 goto err_disable;
     51         }
     52 
     53         BASEADDR = pci_ioremap_bar(pdev, 0);
     54         if (BASEADDR == NULL) {
     55                 /* Something's wrong here, BASEADDR has to be set */
     56                 printk(KERN_ERR "failed to get BASEADDR
    ");
     57                 goto err_release;
     58         }
     59 
     60         /* Done */
     61         cwd_pci = pdev;
     62         return 1;
     63 
     64 err_release:
     65         pci_release_region(pdev, 0);
     66 err_disable:
     67         pci_disable_device(pdev);
     68 err_devput:
     69         return 0;
     70 }
     71 
     72 
     73 static int cwd_probe(struct pci_dev *pdev,
     74                 const struct pci_device_id *ent)
     75 {
     76         int ret;
     77 
     78         cards_found++;
     79         if (cards_found == 1)
     80                 printk(KERN_INFO "Cstl WatchDog Timer Driver v%s
    ",
     81                         CWD_VERSION);
     82 
     83         if (cards_found > 1) {
     84                 printk(KERN_ERR "Cstl driver only supports 1 device
    ");
     85                 return -ENODEV;
     86         }
     87 
     88         /* Check whether or not the hardware watchdog is there */
     89         if (!cwd_getdevice(pdev) || cwd_pci == NULL)
     90                 return -ENODEV;
     91         return 0;
     92 }
     93 
     94 static int cwd_timer_stop(void)
     95 {
     96         /* Returns 0 if the timer was disabled, non-zero otherwise */
     97         return 0;
     98 }
     99 static void cwd_remove(struct pci_dev *pdev)
    100 {
    101         /* Stop the timer before we leave */
    102         cwd_timer_stop();
    103 
    104         /* Deregister */
    105         // misc_deregister(&cwd_miscdev);
    106         iounmap(BASEADDR);
    107         pci_release_region(cwd_pci, 0);
    108         pci_disable_device(cwd_pci);
    109         cwd_pci = NULL;
    110 }
    111 
    112 static void cwd_shutdown(struct pci_dev *pdev)
    113 {
    114         cwd_timer_stop();
    115 }
    116 
    117 
    118 static struct pci_driver cwd_driver = {
    119         .name           = ESB_MODULE_NAME,
    120         .id_table       = cwd_pci_tbl,
    121         .probe          = cwd_probe,
    122         .remove         = cwd_remove,
    123         .shutdown       = cwd_shutdown,
    124 };
    125 
    126 static int __init cwd_demo_start(void)
    127 {
    128     printk(KERN_ALERT "Loading cwd_demo module...
    ");
    129     printk(KERN_ALERT "Hello, I'm cwd_demo
    ");
    130     return pci_register_driver(&cwd_driver);
    131 }
    132 
    133 static void __exit cwd_demo_end(void)
    134 {
    135     pci_unregister_driver(&cwd_driver);
    136     printk(KERN_ALERT "cwd demo Module Unloaded, Goodbye!
    ");
    137 
    138 }
    139 
    140 module_init(cwd_demo_start);
    141 module_exit(cwd_demo_end);
    View Code

    Makefile

     1 ifeq ($(KERNELRELEASE),)
     2         KVERSION = $(shell uname -r)
     3 all:
     4         make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) modules
     5         echo $(shell pwd)
     6 clean:
     7         make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) clean
     8 else
     9         obj-m :=cwd_demo.o
    10 endif
    View Code

    编译加载:

    $ make

    $ sudo insmod cwd_demo.ko

    查看加载结果:

    发现加载失败

    $ tail -n 40 -f /var/log/syslog

    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759632] Hello, I'm cwd_demo
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759666] Cstl WatchDog Timer Driver v0.1
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759740] ------------[ cut here ]------------
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759749] WARNING: CPU: 0 PID: 15113 at /build/buil
    dd/linux-lts-saucy-3.11.0/drivers/pci/pci.c:130 pci_ioremap_bar+0x71/0x80()
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759750] Modules linked in: cwd_demo(OF+) btrfs ra
    id6_pq zlib_deflate xor ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs reiserfs ext2 usblp hello(POF)
    rfcomm bnep bluetooth cirrus ttm drm_kms_helper drm sysimgblt sysfillrect syscopyarea ppdev mac_hid p
    arport_pc i2c_piix4 psmouse serio_raw lp parport floppy [last unloaded: cwd_demo]
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759775] CPU: 0 PID: 15113 Comm: insmod Tainted: P
    F       W  O 3.11.0-15-generic #25~precise1-Ubuntu
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759777] Hardware name: QEMU Standard PC (i440FX +
     PIIX, 1996), BIOS Bochs 01/01/2011
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759778]  0000000000000082 ffff8800367b5b38 ffffff
    ff8173bc5e 0000000000000007
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759781]  0000000000000000 ffff8800367b5b78 ffffff
    ff810653ac ffff88003dba1098
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759783]  ffff88003dba1000 ffff8800367b5c20 ffffff
    ffa01e0000 ffff88003dba1098
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759785] Call Trace:
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759792]  [<ffffffff8173bc5e>] dump_stack+0x46/0x58
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759797]  [<ffffffff810653ac>] warn_slowpath_common+0x8c/0xc0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759799]  [<ffffffff810653fa>] warn_slowpath_null+0x1a/0x20
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759801]  [<ffffffff813aaf91>] pci_ioremap_bar+0x71/0x80
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759805]  [<ffffffffa01de12f>] cwd_probe+0x6f/0x1d0 [cwd_demo]
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759808]  [<ffffffff813acd2b>] local_pci_probe+0x4b/0x80
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759810]  [<ffffffff813ae5a9>] __pci_device_probe+0xd9/0xe0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759813]  [<ffffffff813ae5ea>] pci_device_probe+0x3a/0x60
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759817]  [<ffffffff814948bc>] really_probe+0x6c/0x330
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759819]  [<ffffffff81494d07>] driver_probe_device+0x47/0xa0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759821]  [<ffffffff81494e0b>] __driver_attach+0xab/0xb0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759823]  [<ffffffff81494d60>] ? driver_probe_device+0xa0/0xa0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759825]  [<ffffffff81492aee>] bus_for_each_dev+0x5e/0x90
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759827]  [<ffffffff8149447e>] driver_attach+0x1e/0x20
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759829]  [<ffffffff81493f0c>] bus_add_driver+0x10c/0x290
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759831]  [<ffffffff8149538d>] driver_register+0x7d/0x160
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759834]  [<ffffffffa0032000>] ? 0xffffffffa0031fff
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759836]  [<ffffffff813ad56c>] __pci_register_driver+0x4c/0x50
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759838]  [<ffffffffa003203a>] cwd_demo_start+0x3a/0x1000 [cwd_demo]
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759842]  [<ffffffff8100212a>] do_one_initcall+0xfa/0x1b0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759846]  [<ffffffff810578e3>] ? set_memory_nx+0x43/0x50
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759852]  [<ffffffff81730257>] do_init_module+0x80/0x1d1
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759857]  [<ffffffff810d1af9>] load_module+0x4c9/0x5f0
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759859]  [<ffffffff810cf270>] ? show_initstate+0x50/0x50
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759862]  [<ffffffff810d1cd4>] SyS_init_module+0xb4/0x100
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759866]  [<ffffffff8175099d>] system_call_fastpath+0x1a/0x1f
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759868] ---[ end trace 4d45fe543fa54a73 ]---
    Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759869] failed to get BASEADDR

    分析错误:

      通过内核栈信息,我们知道,代码在调用 pci_ioremap_bar 出现了问题。

      我们之前已经了解到,对PCI设备IO的操作,有两种方式,一种,是IO空间,一种是内存空间。我们这里抄袭了i6300esb的代码,esb采用的是内存空间。

    很容易的想到,我们的外设是不支持内存空间的。

    查看我们的qemu的代码,发现我们确实没有实现相关的代码。

    这个可以通过我们的qemu monitor的 info qtree 来查看。

          dev: cstl-watchdog, id ""
            expiration-ticks = 10 (0xa)
            addr = 05.0
            romfile = ""
            rombar = 1 (0x1)
            multifunction = false
            command_serr_enable = true
            class Class 0880, addr 00:05.0, pci id 1af4:0101 (sub 1af4:1100)
            bar 0: i/o at 0xc090 [0xc09f]

    果真是不支持内存空间。

    其实在PCI的spec文件中,有说明,如果从baro~bar5寄存器中读出来的地址是奇数,表示这是个IO空间,这是的地址要与~0x03UL做与运算,如果是偶数,则表示是内存空间。

            /* here we are testing it is a io space or mem space */
            unsigned int addr = 0;
            pci_read_config_dword(pdev, 0x10, &addr);
            printk(KERN_ERR "get BASEADDR: 0x%x ", addr);

    在我们的log中将会输出以下的结果:

    Jun 30 16:14:30 fsh-virtual-machine kernel: [612625.759872] failed to get get BASEADDR: 0xc91

  • 相关阅读:
    java集合部分原材料
    java--Collection继承结构图
    java--类与类之间的关系
    java--BigDecimal类
    java--生成随机数
    java--枚举类型
    java--数字格式化
    Java--包装类型
    Java--StringBuffer和StringBuilder
    Java--String
  • 原文地址:https://www.cnblogs.com/shaohef/p/3808411.html
Copyright © 2020-2023  润新知