JavaScript is required to for searching.
跳过导航链接
退出打印视图
编写设备驱动程序     Oracle Solaris 10 1/13 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

第 1 部分针对 Oracle Solaris 平台设计设备驱动程序

1.  Oracle Solaris 设备驱动程序概述

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

5.  管理事件和排队任务

6.  驱动程序自动配置

7.  设备访问:程控 I/O

8.  中断处理程序

9.  直接内存访问 (Direct Memory Access, DMA)

10.  映射设备和内核内存

11.  设备上下文管理

12.  电源管理

13.  强化 Oracle Solaris 驱动程序

14.  分层驱动程序接口 (Layered Driver Interface, LDI)

第 2 部分设计特定种类的设备驱动程序

15.  字符设备驱动程序

16.  块设备驱动程序

17.  SCSI 目标驱动程序

18.  SCSI 主机总线适配器驱动程序

19.  网络设备驱动程序

20.  USB 驱动程序

21.  SR-IOV 驱动程序

SR-IOV 简介

SR-IOV 的优点

支持的平台

词汇表

SR-IOV 设备驱动程序概述

物理功能 (Physical Function, PF) 驱动程序

虚拟功能 (Virtual Function, VF) 驱动程序

设备配置参数

pci.conf 文件

设置设备配置参数

Sparc OVM 平台上的 SR-IOV 配置

裸机平台上的 SR-IOV 配置

引导配置序列

SR-IOV 接口汇总

驱动程序 Ioctl

SR-IOV 驱动程序的接口

pci_param_get() 接口

pci_param_get_ioctl() 接口

pci_plist_get() 接口

pci_plist_getvf() 接口

pciv_vf_config() 接口

pci_plist_lookup() 接口

pci_param_free() 接口

pciv_send() 接口

SR-IOV 驱动程序 Ioctl

数据结构

iov_param_ver_info 结构

iov_param_validate 结构

iov_param_desc 结构

IOV_GET_VER_INFO Ioctl

IOV_GET_PARAM_INFO Ioctl

IOV_VALIDATE_PARAM Ioctl

驱动程序回调

驱动程序 Ioctl 的样例代码

第 3 部分生成设备驱动程序

22.  编译、装入、打包和测试驱动程序

23.  调试、测试和调优设备驱动程序

24.  推荐的编码方法

第 4 部分附录

A.  硬件概述

B.  Solaris DDI/DKI 服务汇总

C.  使设备驱动程序支持 64 位

D.  控制台帧缓存器驱动程序

E.  pci.conf 文件

索引

SR-IOV 驱动程序的接口

以下各节介绍了 SR-IOV 驱动程序的接口。

pci_param_get() 接口

SR-IOV 驱动程序必须使用 pci_param_get(9F) 接口来获取当前配置的参数的列表。此接口在驱动程序连接期间或任何其他合适的时间被调用。返回的数据是指向参数列表的指针,包含 PF 及其相应 VF 设备的名称-值信息。

int pci_param_get(dev_info_t *dip, pci_param_t *php)

其中:

dip

指向 dev_info 结构的指针。

php

指向 param 句柄 pci_param_t 的指针。

在调用 pci_param_get 接口后,设备驱动程序应执行以下步骤来获取 PF 和 VF 的参数列表:

  1. 调用 pci_plist_get(9F) 接口来获取 PF 设备的参数列表,调用 pci_plist_getvf(9F) 接口来获取所配置的 VF 的参数列表。

  2. 调用 pci_plist_lookup(9F) 接口来获取设备参数。

  3. 验证所有的 PF 和 VF 参数。

  4. 如果参数与当前配置不匹配,则驱动程序应当使设备连接失败。

  5. 调用 pci_param_free(9F) 接口来释放用于获取 PF 和所配置的 VF 设备的参数的参数句柄指针。请参见示例 21-2


注 - 应在配置 VF 之前完成参数验证。


名称-值对是针对每台设备分别定义的。PF 有一组名称-值对,每个已配置的 VF 也有一组名称-值对。名称-值对是可选的,可以为任何或所有设备省略名称-值对。

示例 21-2 SR-IOV pci_param_get(9F) 例程

    pci_param_t my_params;
pci_plist_t pf_plist;
pci_plist_t  vf_plist[8];
labelp = NULL;
rval = pci_param_get(dip,&my_params);
if (rval || (my_params == NULL)) {
   cmn_err(CE_NOTE, "No params available\n");
goto continue_with_attach;
}
rval = pci_plist_get(my_params, &pf_list);
if (rval || (pf_plist == NULL)) {
        cmn_err(CE_NOTE, "No params for PF \n");
goto continue_with_attach;
}
for (i = 0; i < 8; i++) {
    rval = pci_plist_getvf(my_params, i, &vf_plist[i]);
    if (rval || (vf_plist[i] == NULL)) {
     cmn_err(CE_WARN, "No params for VF %d\n", i);
     continue;
 }
}
pci_param_free(my_params);
/*
* Validate the PF and VF params lists.
* Fail the attach if the params are incompatible or exceed the
* resources available.
*/
continue_with_attach:

pci_param_get_ioctl() 接口

SR-IOV 设备驱动程序可以使用 pci_param_get_ioctl(9F) 接口从 arg 参数中提取 PF 和 VF 设备的参数(如果这些驱动程序实现了 IOV_VALIDATE_PARAM ioctl)。

int pci_param_get_ioctl(dev_info_t *dip, intptr_t arg, int mode,pci_param_t *php)

其中:

dip

指向 dev_info 结构的指针。

arg

通过驱动程序的 ioctl 调用获取的参数

mode

通过驱动程序的 ioctl 调用获取的参数

php

指向通过调用 pci_param_get()pci_param_get_ioctl() 接口获取的 param 句柄 pci_param_t 的指针。

在检索参数后,驱动程序应调用 pci_param_free() 接口来释放在该调用中返回的 param 句柄。

pci_plist_get() 接口

pci_plist_get(9F) 接口用于从通过 pci_param_get(9F) 调用或 pci_param_get_ioctl(9F) 调用获取的 param 句柄中获取参数列表。

int pci_plist_get(pci_param_t param, pci_plist_t *plist_p)

其中:

param

pci_param_get()pci_param_get_ioctl() 接口获取的句柄。

plist_p

指向在成功返回时返回非空 plistpci_plist_t 的指针。

pci_plist_get() 调用返回的 plist 仅适用于 PF 功能。结构 pci_plist_t 支持以下数据类型的数组:

pci_plist_getvf() 接口

pci_plist_getvf(9F) 接口用于获取 VF 设备的名称-值对列表。

int pciv_plist_getvf (pci_param_t param, uint16_t vf_index, pci_plist_t *vfplist_p )

其中:

param

pci_param_get()pci_param_get_ioctl() 接口获取的一个句柄。

vf_index

介于 0 到 #VFS - 1 之间的一个值。

*vfplist_p

指向 pci_plist_t 结构的指针。

pciv_vf_config() 接口

pciv_vf_config(9F) 接口由 SR-IOV 驱动程序使用,用于获取关于 VF 的配置信息,还用于在驱动程序连接期间配置 VF。

#include <sys/sunddi.h>
int pciv_vf_config(dev_info_t *dip, pciv_config_vf_t *vfcfg_p)

其中:

dip

指向 dev_info 结构的指针。

vfcfg_p

指向 pciv_config_vf 结构的指针。

typedef enum { 
                 PCIV_VFCFG_PARAM,
                 PCIV_VF_ENABLE,
                          PCIV_VF_DISABLE
                 PCIV_EVT_VFENABLE_PRE,
                 PCIV_EVT_VFENABLE_POST,
                 PCIV_EVT_VFDISABLE_PRE,
                 PCIV_EVT_VFDISABLE_POST
             } pciv_vf_config_cmd_t;

pciv_config_vf 结构包含以下字段:

typedef struct pciv_config_vf {
               int version;
                pciv_vf_config_cmd_t cmd;
                uint16_t num_vf;
                uint16_t first_vf_offset;
                uint16_t vf_stride;
                boolean_t ari_cap;
                uint32_t page_size;
     } pciv_config_vf_t;

其中:

version

版本号。

cmd

用于指示是否调用此接口来获取配置信息或连接 VF。

  • PCIV_VFCFG_PARAM-获取配置信息

  • PCIV_VF_ENABLE-启用 VF

    • PCIV_EVT_VFENABLE_PRE

    • PCIV_EVT_VFDISABLE_PRE

    • PCIV_EVT_VFENABLE_POST

    • PCIV_EVT_VFDISABLE_POST

num_vf

在后端定义的 VF 的数量。

vf_stride

两个 VF 之间的距离。

first_vf_offset

第一个 VF 与 PF 之间的偏移量。

ari_cap

具有 ARI 功能的分层结构。

page_size

指定系统页大小。

驱动程序首先应在将 cmd 字段设置为 PCIV_VFCFG_PARAM 的情况下调用 pciv_vfconfig() 接口来获取配置信息。然后,驱动程序应在将 cmd 字段设置为 PCIV_VF_ENABLE 的情况下再次调用此接口来配置 VF。

驱动程序可能会返回以下错误代码之一:

DDI_SUCCESS

DDI_FAILURE

PCIV_REQRESET

PCIV_REQREATTACH

在调用 pciv_vf_config() 接口来启用 VF 之前,驱动程序不是必须通过设置 DDI_CB_FLAG_SRIOV 位来注册回调不可。不过,要在 SR-IOV 框架未配置 VF 时接收通知,驱动程序必须在启用 VF 后通过设置 DDI_CB_FLAG_SRIOV 位来注册回调。有关更多信息,请参见驱动程序回调

可支持 VF 的所有 PF 驱动程序应该通过在标志参数中设置 DDI_CB_FLAG_SRIOV 标志的情况下调用 ddi_cb_register(9F) 来告诉 PCIe 框架它们的容量。在驱动程序的连接例程中必须调用 ddi_cb_register() 函数。如果 PF 设备驱动程序在其连接例程中调用 pciv_vf_config() 函数来启用 VF,则 PF 驱动程序应在启用 VF 后调用 ddi_cb_register() 函数。

框架需要使用 DDI_CB_FLAG_SRIOV 标志才能执行以下操作:

pci_plist_lookup() 接口

pci_plist_lookup(9F) 接口可由驱动程序用来查找受支持的各种数据类型的名称-值对。函数将查找与接口名称指示的名称和类型匹配的 nvpair(名称-值对)。如果找到,将修改 nelemval 以分别包含值中的元素数和数据的起始地址。

pci_plist_lookup() 接口支持以下数据类型:

其中:

plist

指向要处理的 pci_plist_t 结构的指针。

name

要搜索的名称-值对的名称。

nelem

存储值中的元素数的地址。

val

数据的起始地址。

pci_plist_lookup() 函数在成功时返回 0,失败时返回某个错误值。支持以下错误值:

DDI_EINVAL

参数无效

ENOENT

未找到匹配的名称-值对

ENOTSUP

编码或解码方法不受支持

pci_param_free() 接口

驱动程序在使用 param 句柄获取设备参数后必须调用 pci_param_free(9F) 接口。此调用将释放由 pci_param_get()pci_param_get_ioctl() 接口分配的资源。

int pci_param_free (pci_param_t param)

其中,param 是从 pci_param_get()pci_param_get_ioctl() 接口获取的句柄。

pciv_send() 接口

pciv_send(9F) 接口由具有 SR-IOV 功能的 PF 和 VF 驱动程序用来彼此进行通信。尽管 VF 驱动程序只能与其 PF 驱动程序进行通信,但 PF 驱动程序可与其任何 VF 驱动程序进行通信。

int pciv_send(dev_info_t *dip, pciv_pvp_req_t *req

其中:

dip

指向 dev_info 结构的指针。

req

指向 pciv_pvp_req_t 结构的指针。

pciv_pvp_req_t 的结构为:

typedef struct pciv_pvp_req {
int pvp_dstfunc;
caddr_t pvp_buf;
size_t pvp_nbyte;
buf_cb_t pvp_cb;
caddr_t pvp_cb_arg;
uint_t pvp_flag;
} pciv_pvp_req_t;

其中:

pvp_dstfunc

如果由 PF 驱动程序调用,则 VF 索引的范围是 1 到 num_vf。如果调用方是 VF 驱动程序,则它应当始终为 PCIV_PF。

pvp_buf

要发送的调用方缓冲区的缓冲区地址。

pvp_nbyte

要传送的字节数,必须小于 8k。

pvp_cb

回调函数指针,如果 pvp_flag 设置为 PCIV_NOWAIT

如果 pvp_flag 设置为 PCIV_NOWAIT,调用将立即返回,并在将 pvp_buf 中的数据传送到目标之前调用 pvp_cb 中的回调例程。随后,将允许调用方在其回调例程中释放缓冲区。

typedef void (*buf_cb_t)(int rc, caddr_t buf, size_t size, caddr_t cb_arg);

其中:

rc

用于传输的 DDI 返回代码。

buf

要发送的调用方缓冲区的缓冲区地址。

size

要传输的字节数。

cb_arg

调用方在调用例程时设置的输入参数。

pvp_cb_arg

pvp_cb 的回调输入参数,如果 pvp_flag 设置为 PCIV_NOWAIT

pvp_flag
  • PCIV_NOWAIT-不等待接收方的响应。

  • PCIV_WAIT-这是缺省状态。等待,直到接收方确认接收传输。

pciv_send() 接口返回以下返回值之一:

DDI_SUCCESS

缓冲区已成功发送。

DDI_ENOTSUP

设备驱动程序不支持此操作。调用方可以使用其他机制,如硬件邮箱。

DDI_EINVAL

pvp_nbytepvp_dstfunc 无效。

DDI_ENOMEM

操作因缺少资源而失败。

DDI_ETRANSPORT

远程端未注册用于处理传入的传输的回调。

DDI_FAILURE

因意外原因失败。