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 驱动程序 Ioctl

SR-IOV 驱动程序 ioctl 用于标识可由管理员配置的特定于设备的参数,并在应用特定配置之前验证此特定配置。以下各节介绍了 ioctl 数据结构和接口。

数据结构

以下各节列出了 PF 驱动程序在实现 ioctl 之前应该定义并初始化的数据结构:

iov_param_ver_info 结构

iov_param_ver_info 结构定义如下:

#define IOV_IOCTL (('I' << 24) | ('O' << 16) | ('V' << 8))
#define IOV_GET_VER_INFO (IOV_IOCTL | 0)
#define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
#define IOV_VALIDATE_PARAM (IOV_IOCTL | 2)
#define IOV_PARAM_DESC_VERSION  1

iov_param_ver_info 结构包含以下字段:

typedef struct iov_param_ver_info {
uint32_t version; 
uint32_t num_params; 
} iov_param_ver_info_t;

其中:

version

版本信息

num_params

参数个数

iov_param_validate 结构

iov_param_validate 结构定义如下:

  #define IOV_IOCTL (('I' << 24) | ('O' << 16) | ('V' << 8))
  #define IOV_GET_VER_INFO (IOV_IOCTL | 0)
  #define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
  #define IOV_VALIDATE_PARAM  (IOV_IOCTL | 2)
  #define IOV_PARAM_DESC_VERSION  1

iov_param_validate 包含以下字段:

typedef struct iov_param_validate {
     char pv_reason[MAX_REASON_LEN + 1];
     int32_t pv_buflen;
     /* encoded buffer containing params */
    char pv_buf[1];  /* size of buf is pv_buflen */          
} iov_param_validate_t;

其中:

pv_reason

ioctl 调用失败时用于解释失败原因的一个 ASCII 字符串

pv_buflen

缓冲区 pv_buf 的长度

pv_buf

包含参数的缓冲区

iov_param_desc 结构

iov_param_desc 结构定义如下:

     #define IOV_IOCTL  (('I' << 24) | ('O' << 16) | ('V' << 8))
  #define IOV_GET_VER_INFO (IOV_IOCTL | 0)
  #define IOV_GET_PARAM_INFO (IOV_IOCTL | 1)
  #define IOV_VALIDATE_PARAM (IOV_IOCTL | 2)
  #define IOV_PARAM_DESC_VERSION  1

iov_param_desc 结构包含以下字段:

typedef struct iov_param_desc {
char pd_name[MAX_PARAM_NAME_SIZE];
char pd_desc[MAX_PARAM_DESC_SIZE];
int32_t pd_flag;   /* applicable for PF or VF or both */
int32_t pd_data_type; /* integer, string, plist */
/* Following 3 are applicable for integer data types */
uint64_t pd_default_value;
uint64_t pd_min64;    
uint64_t pd_max64;
char pd_default_string [MAX_PARAM_DEFAULT_STRING_SIZE];
} iov_param_desc_t; 

其中:

pd_name

ldm(1M) 命令或 pci.conf 文件中使用,用于为参数指定值。

pd_desc

参数的简短说明。

pd_flag

指示参数是仅适用于 PF,还是仅适用于 VF,亦或是同时适用于 PF 和 VF。

pd_default_value

未在 ldm() 命令或 pci.conf 文件中指定参数时由驱动程序指定的值。

pd_min64

指定整数参数值的最小范围。

pd_max64

指定整数参数值的最大范围。

pd_default_string

指定将使用的缺省字符串(如果参数是字符串)。

IOV_GET_VER_INFO Ioctl

实现了 IOV_GET_VER_INFO IOCTL() ioctl 的 SR-IOV 设备驱动程序应在 iov_param_ver_info 结构中设置 versionnum_params 字段,并将值返回到调用函数。调用函数随后将使用 versionnum_params 参数确定使用 IOV_GET_PARAM_INFO() ioctl 调用获取参数描述所需的缓冲区大小。

IOV_GET_PARAM_INFO Ioctl

调用 IOV_GET_PARAM_INFO() ioctl 的驱动程序的一般控制流如下所述:

  1. 保留 iov_param_desc_t 结构的数组,这些结构包含各自支持的每个可配置参数的说明。有关结构说明的信息,请参见 iov_param_desc 结构。

  2. iov_param_desc_t 结构的数组复制到 arg 参数。iov_param_desc_t 结构中的字段是静态字段,可在编译时定义。

    数组中元素的数量是 IOV_GET_VER_INFO() ioctl 调用返回的 num_params 值。缓冲区的大小为 sizeof (iov_param_desc_t) * num_params

IOV_VALIDATE_PARAM Ioctl

对调用 IOV_VALIDATE_PARAM() 的驱动程序的一般控制流程如下所述:

  1. arg 参数发送到 pci_param_get_ioctl() 接口并获取指向 pci_param_t 结构的指针。

  2. param 验证失败时,向 pv_reason 数组写入一个解释性的字符串。

  3. 依次调用 pci_get_plist() 接口和 pci_plist_lookup() 接口来获取设备参数。

  4. 在 PF plist 中查找 vfs 名称-值对以获取要针对此配置的验证而配置的 VF 的数量。驱动程序应使用长度至少为 16 位的整数数据类型查找 vfs 名称-值对。使用 pciv_plist_getvf() 接口获取 VF 设备的 plist 参数。

  5. 在不实际将参数应用于设备的情况下对参数进行验证。

  6. 在找到有效配置时返回 0。


注意

注意 - 上述过程中验证的参数与设备的当前配置毫不相关。它们需要单独进行验证(假定它们可以进一步配置)。如果不单独进行验证,驱动程序应返回 DDI_EINVAL 来指示配置不正确。当发现了无效配置时,驱动程序还应在 iov_param_validate 结构的 pv_reason 字段中提供一个解释性字符串。此字符串会将配置失败的原因告知管理员。


驱动程序回调

DDI 接口 ddi_cb_register()ddi_cb_unregister() 用来注册回调。回调用于事件通知和传入数据通信。回调在传输期间充当每个事件的事件处理程序。

SR-IOV 驱动程序应实现其他回调以在配置或取消配置 VF 前后通知 PF 驱动程序。

驱动程序可以使用以下 DDI 回调注册机制接口实现回调:


注 - 具有 SR-IOV 功能的所有 PF 驱动程序必须使用 ddi_cb_flags_t DDI_CB_FLAG_SRIOV 来通知 Oracle Solaris IOV 框架 PF 驱动程序具有 SR-IOV 功能。


驱动程序 Ioctl 的样例代码

enum ioc_reply
igb_ioctl(igb_t *igb, struct iocblk *iocp, mblk_t *mp)
{
        int rval = 0;
        iov_param_ver_info_t *iov_param_ver;
        iov_param_validate_t pvalidate;
        pci_param_t my_params;
        char reason[81];

if (mp->b_cont == NULL)
        return (IOC_INVAL);
if ((int)iocp->ioc_count < 0)
        return (IOC_INVAL);
switch (iocp->ioc_cmd) {
        case IOV_GET_PARAM_VER_INFO:
            if (iocp->ioc_count < sizeof (iov_param_ver_info_t))
                return (IOC_INVAL);
            iov_param_ver = (iov_param_ver_info_t *)(mp->b_cont->b_rptr);
            iov_param_ver->version = IOV_PARAM_DESC_VERSION;
            iov_param_ver->num_params = NUM_OF_PARAMS;
        return (IOC_REPLY);
        case IOV_GET_PARAM_INFO:
            if (iocp->ioc_count < sizeof (pci_list))
                return (IOC_INVAL);
            memcpy((caddr_t)(mp->b_cont->b_rptr), &pci_list,sizeof (pci_list));
            return (IOC_REPLY);
        case IOV_VALIDATE_PARAM:
            if (iocp->ioc_count <= 0)
                return (IOC_INVAL);
            strcpy(reason, "Failed to read params sent\n");
            rval = pci_param_get_ioctl(igb->dip,(uintptr_t)(mp->b_cont->b_rptr),
                     iocp->ioc_flag | FKIOCTL,&my_params );
            if (rval == 0) {
                rval = validate_params(igb->dip, my_params, reason);
            pci_param_free(my_params);
    }
if (rval) {
        memcpy(mp->b_cont->b_rptr, reason, sizeof (reason));
        iocp->ioc_count = sizeof (reason);
        return (IOC_REPLY);
}
iocp->ioc_count = 0;
return (IOC_REPLY);
iov_param_ver_info_t iov_param_ver;
iov_param_validate_t pvalidate;
pci_param_t    my_params;

switch (cmd) {
case IOV_GET_PARAM_VER_INFO:
        iov_param_ver.version = IOV_PARAM_DESC_VERSION;
        iov_param_ver.num_params = NUM_OF_PARAMS;
        if (ddi_copyout(&iov_param_ver, (caddr_t)arg,
            sizeof (iov_param_ver_info_t), mode) != DDI_SUCCESS)
        return (DEFAULT);
        return (0);
case IOV_GET_PARAM_INFO:
        if (ddi_copyout(&pci_list, (caddr_t)arg,param_list_size, mode) != DDI_SUCCESS)
        return (DEFAULT);
        return (0);
case IOV_VALIDATE_PARAM:
        strcpy(reason, "Failed to read params sent\n");
        rv = pci_param_get_ioctl(state->dip, arg, mode, &my_params);
        if (rv == 0)
            rv = validate_params(state->dip, my_params, reason); 
        else
            return (rv);
        pci_param_free(my_params);
    if (rv) {
        if (ddi_copyout(reason,iov_param_validate_t *)arg)->pv_reason,
             sizeof (reason), mode) != DDI_SUCCESS)
        return (DEFAULT);
 return (rv);
    }
return (0);