linux中PCI子系统补充

相关知识:《linux中pci设备》

很多网络接口卡都是PCI设备,必须与Linux PCI子系统协同工作。新的PCI设备是PCI Express设备.PCI设备都有只读的配置空间,可以通过lspci命令来读取。

       #lspci -xxx可以查看PCI配置空间内容的十六进制表示

       #lspci -xxxx可以查看扩展PCI配置空间内容的十六进制表示

当然linux PCI API提供了3个读取配置空间的方法,位于文件

drivers/pci/access.c中:

pci_read_config_byte, pci_read_config_word, pci_read_config_dword

还有写配置的方法

pci_write_config_byte, pci_write _config_word, pci_write _config_dword

       在Linux PCI子系统中,PCI设备用pci_device_id对象表示,位于文件

include/linux/mod_devicetable.h:

struct pci_device_id {

        __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/

        __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */

        __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */

        kernel_ulong_t driver_data;     /* Data private to the driver */

};

       每个pci设备驱动程序都声明了一个pci_drier对象,位于文件include/linux/pci.h

struct pci_driver {

        struct list_head node;

        const char *name;

        const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */

        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */

        void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */

        int  (*suspend) (struct pci_dev *dev, pm_message_t state);      /* Device suspended */

        int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);

        int  (*resume_early) (struct pci_dev *dev);

        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */

        void (*shutdown) (struct pci_dev *dev);

        int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */

        const struct pci_error_handlers *err_handler;

        const struct attribute_group **groups;

        struct device_driver    driver;

        struct pci_dynids dynids;

}; 

       其中name是PCI设备的名称。

       id_table:支持的pci_device_id对象组

       probe一个对设备进行初始化的方法

       remove释放设备的方法

       suspend:电源管理回调函数,支持电源管理的设备切换到低耗电状态。

       resume:电源管理回调函数,支持电源管理的设备从低耗电状态唤醒。

       PCI设备用结构pci_dev表示,该结构定义在文件

struct pci_dev {

        struct list_head bus_list;      /* node in per-bus list */

        struct pci_bus  *bus;           /* bus this device is on */

        struct pci_bus  *subordinate;   /* bus this device bridges to */

 

        void            *sysdata;       /* hook for sys-specific extension */

        struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */

        struct pci_slot *slot;          /* Physical slot this device is in */

 

        unsigned int    devfn;          /* encoded device & function index */

        unsigned short  vendor;

        unsigned short  device;

        unsigned short  subsystem_vendor;

        unsigned short  subsystem_device;

        unsigned int    class;          /* 3 bytes: (base,sub,prog-if) */

        u8              revision;       /* PCI revision, low byte of class word */

        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */

#ifdef CONFIG_PCIEAER

        u16             aer_cap;        /* AER capability offset */

#endif

        u8              pcie_cap;       /* PCIe capability offset */

        u8              msi_cap;        /* MSI capability offset */

        u8              msix_cap;       /* MSI-X capability offset */

        u8              pcie_mpss:3;    /* PCIe Max Payload Size Supported */

        u8              rom_base_reg;   /* which config register controls the ROM */

        u8              pin;            /* which interrupt pin this device uses */

        u16             pcie_flags_reg; /* cached PCIe Capabilities Register */

        unsigned long   *dma_alias_mask;/* mask of enabled devfn aliases */

 

        struct pci_driver *driver;      /* which driver has allocated this device */

        u64             dma_mask;       /* Mask of the bits of bus address this

                                           device implements.  Normally this is

                                           0xffffffff.  You only need to change

                                           this if your device has broken DMA

                                           or supports 64-bit transfers.  */

        struct device_dma_parameters dma_parms;

 

        pci_power_t     current_state;  /* Current operating state. In ACPI-speak,

                                           this is D0-D3, D0 being fully functional,

                                           and D3 being off. */

        u8              pm_cap;         /* PM capability offset */

        unsigned int    pme_support:5;  /* Bitmask of states from which PME#

                                           can be generated */

        unsigned int    pme_poll:1;     /* Poll device's PME status bit */

        unsigned int    d1_support:1;   /* Low power state D1 is supported */

        unsigned int    d2_support:1;   /* Low power state D2 is supported */

        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */

        unsigned int    no_d3cold:1;    /* D3cold is forbidden */

        unsigned int    bridge_d3:1;    /* Allow D3 for bridge */

        unsigned int    d3cold_allowed:1;       /* D3cold is allowed by user */

        unsigned int    mmio_always_on:1;       /* disallow turning off io/mem

                                                   decoding during bar sizing */

        unsigned int    wakeup_prepared:1;

        unsigned int    runtime_d3cold:1;       /* whether go through runtime

                                                   D3cold, not set for devices

                                                   powered on/off by the

                                                   corresponding bridge */

        unsigned int    ignore_hotplug:1;       /* Ignore hotplug events */

        unsigned int    hotplug_user_indicators:1/* SlotCtl indicators

                                                      controlled exclusively by

                                                      user sysfs */

        unsigned int    d3_delay;       /* D3->D0 transition time in ms */

        unsigned int    d3cold_delay;   /* D3cold->D0 transition time in ms */

 

#ifdef CONFIG_PCIEASPM

        struct pcie_link_state  *link_state;    /* ASPM link state */

#endif

 

        pci_channel_state_t error_state;        /* current connectivity state */

        struct  device  dev;            /* Generic device interface */

        int             cfg_size;       /* Size of configuration space */

 

        /*

         * Instead of touching interrupt line and base address registers

         * directly, use the values stored here. They might be different!

         */

        unsigned int    irq;

        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */

 

        bool match_driver;              /* Skip attaching driver */

        /* These fields are used by common fixups */

        unsigned int    transparent:1;  /* Subtractive decode PCI bridge */

        unsigned int    multifunction:1;/* Part of multi-function device */

        /* keep track of device state */

        unsigned int    is_added:1;

        unsigned int    is_busmaster:1/* device is busmaster */

        unsigned int    no_msi:1;       /* device may not use msi */

        unsigned int    no_64bit_msi:1/* device may only use 32-bit MSIs */

        unsigned int    block_cfg_access:1;     /* config space access is blocked */

        unsigned int    broken_parity_status:1/* Device generates false positive parity */

        unsigned int    irq_reroute_variant:2;  /* device needs IRQ rerouting variant */

        unsigned int    msi_enabled:1;

        unsigned int    msix_enabled:1;

        unsigned int    ari_enabled:1;  /* ARI forwarding */

        unsigned int    ats_enabled:1;  /* Address Translation Service */

        unsigned int    pasid_enabled:1;        /* Process Address Space ID */

        unsigned int    pri_enabled:1;          /* Page Request Interface */

        unsigned int    is_managed:1;

        unsigned int    needs_freset:1/* Dev requires fundamental reset */

        unsigned int    state_saved:1;

        unsigned int    is_physfn:1;

        unsigned int    is_virtfn:1;

        unsigned int    reset_fn:1;

        unsigned int    is_hotplug_bridge:1;

        unsigned int    is_thunderbolt:1/* Thunderbolt controller */

        unsigned int    __aer_firmware_first_valid:1;

        unsigned int    __aer_firmware_first:1;

        unsigned int    broken_intx_masking:1/* INTx masking can't be used */

        unsigned int    io_window_1k:1/* Intel P2P bridge 1K I/O windows */

        unsigned int    irq_managed:1;

        unsigned int    has_secondary_link:1;

        unsigned int    non_compliant_bars:1;   /* broken BARs; ignore them */

        unsigned int    is_probed:1;            /* device probing in progress */

        pci_dev_flags_t dev_flags;

        atomic_t        enable_cnt;     /* pci_enable_device has been called */

 

        u32             saved_config_space[16]; /* config space saved at suspend time */

        struct hlist_head saved_cap_space;

        struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */

        int rom_attr_enabled;           /* has display of the rom attribute been enabled? */

        struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */

        struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */

 

#ifdef CONFIG_PCIE_PTM

        unsigned int    ptm_root:1;

        unsigned int    ptm_enabled:1;

        u8              ptm_granularity;

#endif

#ifdef CONFIG_PCI_MSI

        const struct attribute_group **msi_irq_groups;

#endif

        struct pci_vpd *vpd;

#ifdef CONFIG_PCI_ATS

        union {

                struct pci_sriov *sriov;        /* SR-IOV capability related */

                struct pci_dev *physfn; /* the PF this VF is associated with */

        };

        u16             ats_cap;        /* ATS Capability offset */

        u8              ats_stu;        /* ATS Smallest Translation Unit */

        atomic_t        ats_ref_cnt;    /* number of VFs with ATS enabled */

#endif

#ifdef CONFIG_PCI_PRI

        u32             pri_reqs_alloc; /* Number of PRI requests allocated */

#endif

#ifdef CONFIG_PCI_PASID

        u16             pasid_features;

#endif

        phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */

        size_t romlen; /* Length of ROM if it's not from the BAR */

        char *driver_override; /* Driver name to force a match */

 

        unsigned long priv_flags; /* Private flags for the pci driver */

};

其中driver是分配该设备的驱动程序。

current_state表示当前运行状态。

cfg_size是配置空间的大小。

1.   注册设备

如果要向PCI子系统注册PCI网络设备,需要如下操作:

定义一个pci_driver对象,并调用pci_register_driver宏。

在PCI设备使用前要进行初始化,这个工作由驱动程序调用pci_enable_device()来操作,会分配必要的I/O资源和内存资源。同时还要通过request_irq来指定IRQ处理程序(在设备关闭时要调用free_irq来释放)。

2.   设备特性

  为支持局域网唤醒(Wake-On-LAN)功能,设备驱动程序必须在操作函数集中定义一个set_wol()函数。

  查看设备是否支持局域网唤醒功能,可以通过ethtool命令来进行查看,

猜你喜欢

转载自blog.csdn.net/notbaron/article/details/80346988