首页 文章

PCI驱动程序获取MAC地址

提问于
浏览
0

我正在尝试编写一个可以显示以太网卡MAC地址的pci驱动程序 . 在VM和我的以太网卡上运行Ubuntu是英特尔如下00:08.0以太网控制器:英特尔公司82540EM千兆以太网控制器(rev 02)

我能够从英特尔网站获得相同的数据表,并且根据数据表,它说IO地址映射到第2栏(参见第87页),并且可以使用RAL / RAH寄存器读取MAC,它们位于偏移RAL( 05400h 8 * n; R / W)和RAH(05404h8n; R / W)2 18h IO寄存器基址(位31:2)0b mem

基于这些信息,我写了一个小的PCI驱动程序,但我总是得到MAC作为fff,当我进一步调试时,我看到io_base地址始终为零 .

下面是代码

1 /*
  2  Program to find a device on the PCI sub-system 
  3 */
  4 #define VENDOR_ID       0x8086
  5 #define DEVICE_ID       0x100e
  6 
  7 #include <linux/kernel.h>
  8 #include <linux/module.h>
  9 #include <linux/stddef.h>
 10 #include <linux/pci.h>
 11 #include <linux/init.h>
 12 #include <linux/cdev.h>
 13 #include <linux/device.h>
 14 #include <asm/io.h>
 15 
 16 #define LOG(string...) printk(KERN_INFO string)
 17 
 18 #define CDEV_MAJOR      227
 19 #define CDEV_MINOR      0
 20 
 21 
 22 MODULE_LICENSE("GPL");
 23 
 24 struct pci_dev *pci_dev;
 25 unsigned long mmio_addr;
 26 unsigned long reg_len;
 27 unsigned long *base_addr;
 28 
 29 int device_probe(struct pci_dev *dev, const struct pci_device_id *id);
 30 void device_remove(struct pci_dev *dev);
 31 
 32 struct pci_device_id  pci_device_id_DevicePCI[] =
 33 {
 34         {VENDOR_ID, DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 35 };
 36 
 37 struct pci_driver  pci_driver_DevicePCI =
 38 {
 39   name: "MyPCIDevice",
 40   id_table: pci_device_id_DevicePCI,
 41   probe: device_probe,
 42   remove: device_remove
 43 };
 44 
 45 
 46 int init_module(void)
 47 {
 48         //struct pci_dev *pdev = NULL;
 49         int ret = 0;
 50 
 51         pci_register_driver(&pci_driver_DevicePCI);
 52 
 53         return ret;
 54 }
 55 
 56 void cleanup_module(void)
 57 {
 58         pci_unregister_driver(&pci_driver_DevicePCI);
 59 
 60 }
 61 
 62 #define REGISTER_OFFSET 0x05400
 64 int device_probe(struct pci_dev *dev, const struct pci_device_id *id)
 65 {
 66         int ret;
 67         int bar = 2; // Bar to be reserved
 68         unsigned long io_base = 0;
 69         unsigned long mem_len = 0;
 70         unsigned int register_data = 0;
 71 
 72         LOG("Device probed");
 73 
 74         /* Reserve the access to PCI device */
 75         ret = pci_request_region(dev, bar, "my_pci");
 76         if (ret) {
 77                 printk(KERN_ERR "request region failed :%d\n", ret);
 78                 return ret;
 79         }
 80 
 81         ret  = pci_enable_device(dev);
 82         if (ret < 0 ) LOG("Failed while enabling ... ");
 83 
 84         io_base = pci_resource_start(dev, bar);
 85         mem_len = pci_resource_len(dev, bar);
 86 
 87         request_region(io_base, mem_len, "my_pci");
 88         register_data = inw(io_base + REGISTER_OFFSET);
 89         printk(KERN_INFO "IO base = %lx", io_base);
 90         printk(KERN_INFO "MAC = %x", register_data);
 91 
 92         return ret;
 93 }
 94 
95 void device_remove(struct pci_dev *dev)
 96 {
 97   pci_release_regions(dev);
 98   pci_disable_device(dev);
 99 }
100

lspci -x输出我的卡00:08.0以太网控制器:Intel公司82540EM千兆以太网控制器(转02)00:86 80 0e 10 07 00 30 02 02 00 00 02 00 40 00 00 10:00 00 00 f0 00 00 00 00 41 d2 00 00 00 00 00 00 20:00 00 00 00 00 00 00 00 00 00 00 86 80 1e 00 30:00 00 00 00 00 00 00 00 00 00 00 00 09 01 ff 00

谁能让我知道我做错了什么?

1 回答

  • 0

    我修改了你的代码并评论了变化 . 我已删除所有现有注释以避免混淆,并且仅修改了探测功能 .

    /* We need a place to store a logical address for unmapping later */
    static void* logical_address;
    
    int device_probe(struct pci_dev *dev, const struct pci_device_id *id)
    {
        int ret;
        int bar_mask;          /* BAR mask (this variable) and the integer BAR */
        int requested_bar = 2; /* (this variable) are not the same thing, so give them */
                               /* separate variables */
        resource_size_t io_base = 0; /* use kernel macros instead of built-in datatypes */
        resource_size_t mem_len = 0;
        unsigned int register_data = 0;
    
        LOG("Device probed");
    
        /* add this call to get the correct BAR mask */
        bar_mask = pci_select_bars(dev, 0);
    
        /* switched order - enable device before requesting memory */
        ret  = pci_enable_device(dev);
        if (ret < 0 ) LOG("Failed while enabling ... ");
    
        /* for this call, we want to pass the BAR mask, NOT the integer bar we want */
        ret = pci_request_region(dev, bar_mask, "my_pci");
    
        if (ret) {
            printk(KERN_ERR "request region failed :%d\n", ret);
            return ret;
        }
    
        /* it is in THESE calls that we request a specific BAR */
        io_base = pci_resource_start(dev, requested_bar);
        mem_len = pci_resource_len(dev, requested_bar);
    
        /* you don't need to request anything again, so get rid of this line: */
        /* request_region(io_base, mem_len, "my_pci"); */
    
        /* you're missing an important step: we need to translate the IO address
         * to a kernel logical address that we can actually use. Add a call to
         * ioremap()
         */
    
        logical_address = ioremap(io_base, mem_len);
    
        /* we need to use the logical address returned by ioremap(), not the physical
         * address returned by resource_start
         */
        register_data = inw(logical_address + REGISTER_OFFSET);
        printk(KERN_INFO "IO base = %lx", io_base);
        printk(KERN_INFO "MAC = %x", register_data);
    
        return ret;
    }
    

    您需要在device_remove()例程中添加对iounmap()的相应调用 . 看看Intel E100E driver source code的一些好例子 .

相关问题