JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Writing Device Drivers     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

Part I Designing Device Drivers for the Oracle Solaris Platform

1.  Overview of Oracle Solaris Device Drivers

2.  Oracle Solaris Kernel and Device Tree

3.  Multithreading

4.  Properties

5.  Managing Events and Queueing Tasks

6.  Driver Autoconfiguration

7.  Device Access: Programmed I/O

8.  Interrupt Handlers

9.  Direct Memory Access (DMA)

10.  Mapping Device and Kernel Memory

11.  Device Context Management

12.  Power Management

13.  Hardening Oracle Solaris Drivers

14.  Layered Driver Interface (LDI)

Part II Designing Specific Kinds of Device Drivers

15.  Drivers for Character Devices

16.  Drivers for Block Devices

17.  SCSI Target Drivers

18.  SCSI Host Bus Adapter Drivers

19.  Drivers for Network Devices

20.  USB Drivers

21.  SR-IOV Drivers

Introduction to SR-IOV

Benefits of SR-IOV

Supported Platforms

Glossary

Overview of SR-IOV Device Driver

Physical Function (PF) Driver

Virtual Function (VF) Driver

Device Configuration Parameters

pci.conf File

Setting Device Configuration Parameters

SR-IOV Configuration on Sparc OVM Platform

SR-IOV Configuration on Bare Metal Platforms

Boot Configuration Sequence

SR-IOV Interfaces Summary

Driver Ioctls

Interfaces for SR-IOV Drivers

pci_param_get() Interface

pci_param_get_ioctl() Interface

pci_plist_get() Interface

pci_plist_getvf() Interface

pciv_vf_config() Interface

pci_plist_lookup() Interface

pci_param_free() Interface

pciv_send() Interface

SR-IOV Driver Ioctls

Data Structures

iov_param_ver_info Structure

iov_param_validate Structure

iov_param_desc Structure

IOV_GET_VER_INFO Ioctl

IOV_GET_PARAM_INFO Ioctl

IOV_VALIDATE_PARAM Ioctl

Driver Callbacks

Sample Code for Driver Ioctls

Part III Building a Device Driver

22.  Compiling, Loading, Packaging, and Testing Drivers

23.  Debugging, Testing, and Tuning Device Drivers

24.  Recommended Coding Practices

Part IV Appendixes

A.  Hardware Overview

B.  Summary of Oracle Solaris DDI/DKI Services

C.  Making a Device Driver 64-Bit Ready

D.  Console Frame Buffer Drivers

E.  pci.conf File

Index

SR-IOV Driver Ioctls

The SR-IOV driver ioctls are used to identify the device specific parameters that can be configured by the administrator and to validate a specific configuration before it is applied. The following sections describe the ioctls data structures and the interfaces.

Data Structures

The following sections list the data structures that the PF driver should define and initialize before implementing the ioctls:

iov_param_ver_info Structure

The iov_param_ver_info structure is defined as follows:

#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

The iov_param_ver_info structure contains the following fields:

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

where:

version

Version information

num_params

Number of parameters

iov_param_validate Structure

The iov_param_validate structure is defined as follows:

  #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

The iov_param_validate contains the following fields:

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;

where:

pv_reason

An ASCII string that explains the reason for failure if the ioctl call fails.

pv_buflen

Length of buffer pv_buf

pv_buf

Buffer containing the parameters

iov_param_desc Structure

The iov_param_desc structure is defined as follows:

     #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

The structure iov_param_desc contains the following fields:

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; 

where:

pd_name

Used in the ldm(1M) command or the pci.conf file to assign a value to the parameter.

pd_desc

A brief description of the parameter.

pd_flag

Indicates if the parameter is applicable to only PF, only VF or applicable to both PF and VF.

pd_default_value

Value assigned by the driver if parameter is not specified in the ldm() command or pci.conf file.

pd_min64

Specifies the minimum range of values for the integer parameter

pd_max64

Specifies the maximum range of values for the integer parameter.

pd_default_string

Specifies the default string that will be used, if parameter is a string.

IOV_GET_VER_INFO Ioctl

SR-IOV device drivers that implement the IOV_GET_VER_INFO IOCTL() ioctl should set the version and the num_params fields in the iov_param_ver_info structure and return the values to the calling function. The calling function then uses the version and num_params parameters to determine the size of buffer required to get parameter descriptions using the IOV_GET_PARAM_INFO() ioctl call.

IOV_GET_PARAM_INFO Ioctl

The general flow of control for a driver that calls the IOV_GET_PARAM_INFO() ioctl is as follows:

  1. Keep an array of iov_param_desc_t structures which contain description for each of the configurable params that are supported by the structure. See the iov_param_desc structure for the structure description.

  2. Copy out the array of iov_param_desc_t structures to the arg parameter. The fields in the iov_param_desc_t structure are static and can be defined at compile time.

    The number of elements in the array is the num_params value returned by the IOV_GET_VER_INFO() ioctl call. The size of the buffer is sizeof (iov_param_desc_t) * num_params

IOV_VALIDATE_PARAM Ioctl

The general flow of control for a driver that calls the IOV_VALIDATE_PARAM() is as follows:

  1. Send the arg parameter to the pci_param_get_ioctl() interface and obtain a pointer to the pci_param_t structure.

  2. Write an explanatory string to the pv_reason array if param validation fails.

  3. Call the pci_get_plist() interface followed by the pci_plist_lookup() interface to obtain the device parameters.

  4. Lookup the vfs name-value pair in the PF plist to obtain the number of VFs to be configured for the validation of this configuration. The drivers should use integer data type of at least 16 bits to look up vfs name-value pair. Use the pciv_plist_getvf() interface to get the plist parameter for the VF devices.

  5. Validate the parameters without actually applying them to the device.

  6. Return 0 when a valid configuration is found.


Caution

Caution - The parameters validated in the above procedure are not related to the current configuration of the device in any way. They need to be validated separately assuming they could be a future configuration. If not, the driver should return DDI_EINVAL to indicate improper configuration. The driver should also provide an explanatory string in the pv_reason field in the iov_param_validate structure when invalid configurations are found. This string informs the administrator why the configuration failed.


Driver Callbacks

The DDI interfaces ddi_cb_register() and ddi_cb_unregister() are used to register callbacks. Callbacks are used for event notifications and incoming data traffic. Callbacks serve as an event handler for each event during transmission.

The SR-IOV driver should implement additional callbacks to inform the PF driver before and after configuring or unconfiguring the VFs.

The driver can implement the callbacks using the following DDI callback registration mechanism interfaces:


Note - All PF drivers that are SR-IOV capable must use the ddi_cb_flags_t DDI_CB_FLAG_SRIOV to inform the Oracle Solaris IOV framework that the PF drivers are SR-IOV capable.


Sample Code for Driver Ioctls

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