首页 > 其他分享 >pcie驱动

pcie驱动

时间:2022-12-05 16:46:34浏览次数:39  
标签:VERSION PCI int unsigned pcie pci 驱动 CFG80211

1. 驱动

mtk wifi驱动基于pci进行扩展,第一个文件:/os/linux/pci_main_dev.c

文件用于创建和注册基于pci接口的网络设备,PCI设备上有三种地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在启动时负责对所有PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件/proc/pci中列出所有找到的PCI设备,以及这些设备的参数和属性。

Linux驱动程序通常使用结构(struct)来表示一种设备,而结构体中的变量则代表某一具体设备,该变量存放了与该设备相关的所有信息。好的驱动程序都应该能驱动多个同种设备,每个设备之间用次设备号进行区分,如果采用结构数据来代表所有能由该驱动程序驱动的设备,那么就可以简单地使用数组下标来表示次设备号。

1.1 数据结构

1 static struct pci_device_id rt_pci_tbl[] DEVINITDATA =

{

{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3091_PCIe_DEVICE_ID)},

#ifdef RT8592

{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC8592_PCIe_DEVICE_ID)},

#endif /* RT8592 */

#ifdef MT76x2

{PCI_DEVICE(0x1400, NIC7650_PCIe_DEVICE_ID)},

{PCI_DEVICE(0x1400, NIC7662_PCIe_DEVICE_ID)},

{PCI_DEVICE(MTK_PCI_VENDOR_ID, NIC7662_PCIe_DEVICE_ID)},

{PCI_DEVICE(MTK_PCI_VENDOR_ID, NIC7632_PCIe_DEVICE_ID)},

{PCI_DEVICE(MTK_PCI_VENDOR_ID, NIC7612_PCIe_DEVICE_ID)},

{PCI_DEVICE(MTK_PCI_VENDOR_ID, NIC7602_PCIe_DEVICE_ID)},

#endif /* MT76x2 */

{} /* terminate list */

};

struct pci_device_id {

         __u32 vendor,device;                    //厂商和设备ID

         __u32 subvendor,subdevice;          //子系统和设备ID

         __u32 class,class_mask;                //类、子类、prog-if三元组

         kernel_ulong_t driver_data;           //驱动私有数据

pci_device_id 用MODULE_DEVICE_TABLE映射到用户空间。
 

2 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;

struct device_driver driver;

struct pci_dynids dynids;

};
 

3 struct pci_dev {

struct list_head bus_list;

/* 总线设备链表元素bus_list:每一个pci_dev结构除了链接到全局设备链表中外,还会通过这个成员连接到其所属PCI总线的设备链表中。每一条PCI总线都维护一条它自己的设备链表视图,以便描述所有连接在该PCI总线上的设备,其表头由PCI总线的pci_bus结构中的 devices成员所描述t*/

struct pci_bus *bus;

/* 总线指针bus:指向这个PCI设备所在的PCI总线的pci_bus结构。因此,对于桥设备而言,bus指针将指向桥设备的主总线(primary bus),也即指向桥设备所在的PCI总线*/

struct pci_bus *subordinate;

/* 指针subordinate:指向这个PCI设备所桥接的下级总线。这个指针成员仅对桥设备才有意义,而对于一般的非桥PCI设备而言,该指针成员总是为NULL*/

 

void *sysdata;

/* 无类型指针sysdata:指向一片特定于系统的扩展数据*/

 

struct proc_dir_entry *procent;

/* 指针procent:指向该PCI设备在/proc文件系统中对应的目录项*/

 

unsigned int devfn;

/* devfn:这个PCI设备的设备功能号,也成为PCI逻辑设备号(0-255)。其中bit[7:3]是物理设备号(取值范围0-31),bit[2:0]是功能号(取值范围0-7)。 */

 

unsigned short vendor;

/* vendor:这是一个16无符号整数,表示PCI设备的厂商ID*/

 

unsigned short device;

/*device:这是一个16无符号整数,表示PCI设备的设备ID */


unsigned short subsystem_vendor;

/* subsystem_vendor:这是一个16无符号整数,表示PCI设备的子系统厂商ID*/

 

unsigned short subsystem_device;

/* subsystem_device:这是一个16无符号整数,表示PCI设备的子系统设备ID。*/

 

unsigned int class;

/* class:32位的无符号整数,表示该PCI设备的类别,其中,bit[7:0]为编程接口,bit[15:8]为子类别代码,bit [23:16]为基类别代码,bit[31:24]无意义。显然,class成员的低3字节刚好对应与PCI配置空间中的类代码*/

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

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

u8 pcie_cap; /* PCI-E capability offset */

u8 msi_cap; /* MSI capability offset */

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

u8 pcie_mpss:3; /* PCI-E 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 PCI-E Capabilities Register */

 

struct pci_driver *driver;

/* 指针driver:指向这个PCI设备所对应的驱动程序定义的pci_driver结构。每一个pci设备驱动程序都必须定义它自己的pci_driver结构来描述它自己。*/

 

u64 dma_mask;

/*dma_mask:用于DMA的总线地址掩码,一般来说,这个成员的值是0xffffffff。数据类型dma_addr_t定义在include/asm/types.h中,在x86平台上,dma_addr_t类型就是u32类型*/

 

struct device_dma_parameters dma_parms;

 

pci_power_t current_state;

/* 当前操作状态 */

u8 pm_cap; /* PM capability offset */

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

can be generated */

unsigned int pme_interrupt:1;

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 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 d3_delay; /* D3->D0 transition time in ms */

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

 

pci_channel_state_t error_state; /* current connectivity state */

struct device dev; /* Generic device interface */

 

int cfg_size;

/* 配置空间的大小 */

 

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; /* Transparent 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 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 is_managed:1;

unsigned int is_pcie:1; /* Obsolete. Will be removed.

Use pci_is_pcie() instead */

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 __aer_firmware_first_valid:1;

unsigned int __aer_firmware_first:1;

unsigned int broken_intx_masking:1;

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

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_PCI_MSI

struct list_head msi_list;

struct kset *msi_kset;

#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 */

};

struct pci_ats *ats; /* Address Translation Service */

#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

};
 

1.2关键函数

1.2.1 rt_pci_init_module

调用函数pci_register_driver(&rt_pci_driver); 注册设备

1.2.2 rt_pci_probe

主要函数分析

1 rv = pci_enable_device(pdev)

唤醒和使能设备
 

2 rv = pci_request_regions(pdev, print_name)

函数通知内核,当前PCI将使用这些内存地址,其他设备不能再使用了
 

3 csr_addr = (unsigned long) ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));

物理地址与虚拟地址进行映射
 

4 pci_set_master(pdev);

设置设备具有获得总线的能力,即调用这个函数,使设备具备申请使用PCI总线的能力
 

5 rv = RTMPAllocAdapterBlock(handle, &pAd);

适配器申请内存, 并进行初始化。(包括beaconbuf申请\rx ring \tx ring 等初始化)。
 

6 RTMP_DRIVER_PCI_CSR_SET(pAd, csr_addr);

设置pci 对应的虚拟地址映射
 

7 RTMP_DRIVER_PCIE_INIT(pAd, pdev);

设置wlan芯片相关寄存器设置 以及pcie的初始化,调用mac目录下的接口函数,对寄存器进行设置.
 

8 net_dev = RtmpPhyNetDevInit(pAd, &netDevHook);

实现物理层网络设备的创建、初始化、以及相关结构接口的初始化,主要是结构体的创建。
 

9 CFG80211_Register(pAd, &(pdev->dev), net_dev);

实现cfg80211网络设备模块的注册, 提供设备cfg80211接口命令:
os/linux/cfg80211/cfg80211.c
struct cfg80211_ops CFG80211_Ops = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
 .set_beacon = CFG80211_OpsSetBeacon,
 .add_beacon = CFG80211_OpsAddBeacon,
 .del_beacon = CFG80211_OpsDelBeacon,
#else
 .start_ap     = CFG80211_OpsStartAp,
 .change_beacon = CFG80211_OpsChangeBeacon,
 .stop_ap     = CFG80211_OpsStopAp,
#endif /* LINUX_VERSION_CODE 3.4 */

 /* set channel for a given wireless interface */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
 //.set_monitor_channel = CFG80211_OpsMonitorChannelSet,
#else
 .set_channel      = CFG80211_OpsChannelSet,
#endif /* LINUX_VERSION_CODE: 3.6.0 */
 
 /* change type/configuration of virtual interface */
 .change_virtual_intf = CFG80211_OpsVirtualInfChg,
 .add_virtual_intf           = CFG80211_OpsVirtualInfAdd,
 .del_virtual_intf           = CFG80211_OpsVirtualInfDel,

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
 .start_p2p_device = CFG80211_start_p2p_device,
 .stop_p2p_device = CFG80211_stop_p2p_device,
#endif /* LINUX_VERSION_CODE: 3.6.0 */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
 /* request to do a scan */
 /*
 Note: must exist whatever AP or STA mode; Or your kernel will crash
 in v2.6.38.
 */
 .scan = CFG80211_OpsScan,
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
 /* set the transmit power according to the parameters */
 .set_tx_power = CFG80211_OpsTxPwrSet,
 /* store the current TX power into the dbm variable */
 .get_tx_power = CFG80211_OpsTxPwrGet,
 /* configure WLAN power management */
 .set_power_mgmt = CFG80211_OpsPwrMgmt,
 /* get station information for the station identified by @mac */
 .get_station = CFG80211_OpsStaGet,
 /* dump station callback */
 .dump_station = CFG80211_OpsStaDump,
 /* notify that wiphy parameters have changed */
 .set_wiphy_params = CFG80211_OpsWiphyParamsSet,
 /* add a key with the given parameters */
 .add_key = CFG80211_OpsKeyAdd,
 /* get information about the key with the given parameters */
 .get_key = CFG80211_OpsKeyGet,
 /* remove a key given the @mac_addr */
 .del_key = CFG80211_OpsKeyDel,
 /* set the default key on an interface */
 .set_default_key = CFG80211_OpsKeyDefaultSet,
#ifdef DOT11W_PMF_SUPPORT
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
 .set_default_mgmt_key = CFG80211_OpsMgmtKeyDefaultSet,
#endif /* LINUX_VERSION_CODE */
#endif /* DOT11W_PMF_SUPPORT */

 /* connect to the ESS with the specified parameters */
 .connect = CFG80211_OpsConnect,
 /* disconnect from the BSS/ESS */
 .disconnect = CFG80211_OpsDisconnect,
#endif /* LINUX_VERSION_CODE */

#ifdef RFKILL_HW_SUPPORT
 /* polls the hw rfkill line */
 .rfkill_poll = CFG80211_OpsRFKill,
#endif /* RFKILL_HW_SUPPORT */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
 /* get site survey information */
 //.dump_survey = CFG80211_OpsSurveyGet,
 /* cache a PMKID for a BSSID */
 .set_pmksa = CFG80211_OpsPmksaSet,
 /* delete a cached PMKID */
 .del_pmksa = CFG80211_OpsPmksaDel,
 /* flush all cached PMKIDs */
 .flush_pmksa = CFG80211_OpsPmksaFlush,
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
 /*
 Request the driver to remain awake on the specified
 channel for the specified duration to complete an off-channel
 operation (e.g., public action frame exchange).
 */
 .remain_on_channel = CFG80211_OpsRemainOnChannel,
 /* cancel an on-going remain-on-channel operation */
 .cancel_remain_on_channel =  CFG80211_OpsCancelRemainOnChannel,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37))
 /* transmit an action frame */
 .action = NULL,
#else
 .mgmt_tx                    = CFG80211_OpsMgmtTx,
#endif /* LINUX_VERSION_CODE */
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
  .mgmt_tx_cancel_wait       = CFG80211_OpsTxCancelWait,
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
 /* configure connection quality monitor RSSI threshold */
 .set_cqm_rssi_config = NULL,
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
 /* notify driver that a management frame type was registered */
 .mgmt_frame_register = CFG80211_OpsMgmtFrameRegister,
#endif /* LINUX_VERSION_CODE */

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
 /* set antenna configuration (tx_ant, rx_ant) on the device */
 .set_antenna = NULL,
 /* get current antenna configuration from device (tx_ant, rx_ant) */
 .get_antenna = NULL,
#endif /* LINUX_VERSION_CODE */
 .change_bss                             = CFG80211_OpsChangeBss,
 .del_station                            = CFG80211_OpsStaDel,
 .add_station                            = CFG80211_OpsStaAdd,
 .change_station                         = CFG80211_OpsStaChg,
// .set_bitrate_mask                       = CFG80211_OpsBitrateSet,
#ifdef CONFIG_NL80211_TESTMODE
        .testmode_cmd                           = CFG80211_OpsTestModeCmd,
#endif /* CONFIG_NL80211_TESTMODE */
};

 

10 RTMP_DRIVER_OP_MODE_GET(pAd, &OpMode);

获取当前设备wlan设备的工作模式
 

11 rv = RtmpOSNetDevAttach(OpMode, net_dev, &netDevHook);

实现网络设备相应回调函数的初始化以及网络设备的注册
 

12 RtmpOSNetDevAddrSet(OpMode, net_dev, &mac_addr[0], NULL);

设置网络设备的mac地址

注释: 一般调用ioctl接口实现一些相关命令处理,函数接口 RTMP_COM_IoctlHandle()

位置/src/common/comm_cfg.c文件
 

1.2.3 rt_pci_resume

驱动唤醒时调用函数.
1 调用函数rt28xx_open,调用函数进行网络设备相关初始化

 
————————————————
版权声明:本文为CSDN博主「smartvxworks」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/smartvxworks/article/details/124353938

标签:VERSION,PCI,int,unsigned,pcie,pci,驱动,CFG80211
From: https://www.cnblogs.com/hshy/p/16952711.html

相关文章

  • PCIe AER
    ConceptsAER:AdvanceerrorreportingPCIe提供两种报错机制:baselinecapability和AERcapabilityBaselinecapabilityisrequiredbyallPCIecomponentsproviding......
  • 华为4g模块 linux驱动程序,定制Android之4G-LTE模块驱动
    定制Android之4G-LTE模块驱动一.        简介本文讲述在Android内核中,添加中国移动4G-LTE制式华为MU909模块驱动,实现通过4G上网业务,电话业务,短信业务。CPU:Sams......
  • UVC设备端驱动的实现原理分析
    UVC工作原理:关于UVC的实现方式,UVC驱动分为设备端和主机端,根据linux内核的实现,貌似设备端的实现源码头部的版本信息描述为“USBVideoClassGadgetdriver”,而主机端的实......
  • PCIE 上位机 介绍
    本文为明德扬原创文章,转载请注明出处!开发环境:windows开发平台:QT5.11.31、PCIE上位机测试过程FPGA将数据传到芯片中,通过pcie再将芯片算完的数传给上位机。目标:1.实现上位机的......
  • 关闭U盘提示“此驱动器存在问题请扫描并修复”
    这个通知来自设置-》通知和操作里的自动播放关闭它即可。 如果你的电脑看不到这,或是出现*某些设置已隐藏或由你的组织管理 管理员命令提示符下键入以下命令:这......
  • VK1625是一种64*8点 LCD液晶段码屏显示驱动控制电路(IC/芯片),可兼容替代市面1625,具省电
    产品品牌:永嘉微电/VINKA产品型号:VK1625封装形式:LQFP100/QFP100/DICE概述:VK1625是一个点阵式存储映射的LCD驱动器,可支持最大512点(64EGx8COM)的LCD屏。单片机可通过3/4线串......
  • MasaFramework -- 领域驱动设计
    概念什么是领域驱动设计领域驱动的主要思想是,利用确定的业务模型来指导业务与应用的设计和实现。主张开发人员与业务人员持续地沟通和模型的持续迭代,从而保证业务模型......
  • 驱动开发学习笔记---块设备
    一、块设备简介块设备驱动是存储设备驱动,块设备驱动相比字符设备驱动的主要区别如下:①、块设备只能以块为单位进行读写访问,块是linux虚拟文件系统(VFS)基本的数据传输......
  • Ubuntu22.04+Nvidia驱动+Cuda11.8+cudnn8.6
    Ubuntu22.04+Nvidia驱动+Cuda11.8一、准备环境ubuntu22.04nvidia显卡这里使用的是RTX3060已安装Python3.10二、安装pip3#安装sudoaptinstallpython3-pip#升级sudopi......
  • PCIE XDMA IP核介绍(附列表)
    1.PCIE的发送和接收数据本工程的目的是在XC7K325tffg的平台上实现pcie的数据发送和接收,速率8通道2.5GB/s,首先看下本工程的PCIE部分的结构:这是PCIEIP核,主要用来发送数据,发......