Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
C.  Making a Device Driver 64-Bit Ready General Conversion Steps Check Changed Fields in DDI Data Structures scsi_pkt Structure Changes  Previous   Contents   Next 
   
 

Check Changed Arguments of DDI Functions

Some DDI function argument data types have been changed. These routines are listed below.

getrbuf() Argument Changes

struct buf *getrbuf(int sleepflag);

In previous releases, sleepflag was defined as a type long.

drv_getparm() Argument Changes

int drv_getparm(unsigned int parm, void *value_p);

In previous releases, value_p was defined as type unsigned long.

In the 64-bit kernel, drv_getparm(9F) can be used to fetch both 32-bit and 64-bit quantities, yet the interface does not define the data types of these quantities, which encourages simple programming errors.

The following new routines offer a safer alternative:

clock_t           ddi_get_lbolt(void);
time_t            ddi_get_time(void);
cred_t            *ddi_get_cred(void);
pid_t             ddi_get_pid(void);

Driver writers are strongly urged to use these routines instead of drv_getparm(9F).

delay() and timeout () Argument Changes

void delay(clock_t ticks);
timeout_id_t timeout(void (*func)(void *), void *arg, clock_t ticks);

The ticks argument to the delay(9F) and timeout(9F) routines has been changed from long to clock_t.

rmallocmap() and rmallocmap_wait() Argument Changes

struct map *rmallocmap(size_t mapsize);
struct map *rmallocmap_wait(size_t mapsize);

The mapsize argument to thermallocmap(9F) and rmallocmap_wait(9F) routines has been changed from ulong_t to size_t.

scsi_alloc_consistent_buf() Argument Changes

struct buf *scsi_alloc_consistent_buf(struct scsi_address *ap,
        struct buf *bp, size_t datalen, uint_t bflags,
        int (*callback )(caddr_t), caddr_t arg);

In previous releases, datalen was defined as an int and bflags was defined as a ulong.

uiomove() Argument Changes

int uiomove(caddr_t address, size_t nbytes,
        enum uio_rw rwflag, uio_t *uio_p);

The nbytes argument was defined as a type long, but because it represents a size in bytes, size_t is more appropriate.

cv_timedwait() and cv_timedwait_sig() Argument Changes

int cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t timeout);
int cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp,    clock_t timeout);

In previous releases, the timeout argument to the cv_timedwait(9F) and cv_timedwait_sig(9F) routines was defined to be of type long. Because they represent time in ticks, clock_t is more appropriate.

ddi_device_copy() Argument Changes

int ddi_device_copy(ddi_acc_handle_t src_handle,
        caddr_t src_addr, ssize_t src_advcnt,
        ddi_acc_handle_t dest_handle, caddr_t dest_addr,
        ssize_t dest_advcnt, size_t bytecount, uint_t dev_datasz);

The src_advcnt, dest_advcnt, dev_datasz arguments have changed type. These were previously defined as long, long, and ulong_t respectively.

ddi_device_zero() Argument Changes

int ddi_device_zero(ddi_acc_handle_t handle,
        caddr_t dev_addr, size_t bytecount, ssize_t dev_advcnt,
        uint_t dev_datasz):

In previous releases, dev_advcnt was defined as a type long and dev_datasz as a ulong_t.

ddi_dma_mem_alloc() Argument Changes

int ddi_dma_mem_alloc(ddi_dma_handle_t handle,
        size_t length, ddi_device_acc_attr_t *accattrp,
        uint_t flags, int (*waitfp)(caddr_t), caddr_t arg,
        caddr_t *kaddrp, size_t *real_length,
        ddi_acc_handle_t *handlep);

In previous releases, length, flags, and real_length were defined with types uint_t, ulong_t, and uint_t *.

Modify Routines That Handle Data Sharing

If a device driver shares data structures that contain longs or pointers with a 32-bit application using ioctl(9E), devmap(9E), or mmap(9E), and the driver is recompiled for a 64-bit kernel, the binary layout of data structures will be incompatible. If a field is currently defined in terms of type long, and there is no actual need for 64-bit data items, change the data structure to use data types that remain as 32-bit quantities (int and unsigned int). Otherwise, the driver needs to be aware of the different structure shapes for ILP32 and LP64 and determine whether there is a model mismatch between the application and the kernel.

To handle potential data model differences, the ioctl(), devmap(), and mmap() driver entry points, which interact directly with user applications, need to be written to determine whether the argument came from an application using the same data model as the kernel.

Data Sharing in ioctl()

To determine whether there is a model mismatch between the application and the driver, the driver uses the FMODELS mask to determine the model type from the ioctl() mode argument. The following values are OR-ed into mode to identify the application data model:

  • FLP64 - Application uses the LP64 data model

  • FILP32 - Application uses the ILP32 data model.

The code examples in "I/O Control Support for 64-Bit Capable Device Drivers" show how this can be handled using ddi_model_convert_from(9F).

Data Sharing in devmap()

To enable a 64-bit driver and a 32-bit application to share memory, the binary layout generated by the 64-bit driver must be the same as consumed by the 32-bit application. The mapped memory being exported to the application might need to contain data-model-dependent data structures.

Few memory mapped devices face this problem because the device registers do not change size when the kernel data model changes. However, some pseudo-devices that export mappings to the user address space might want to export different data structures to ILP32 or LP64 applications. To determine whether there is a data model mismatch, devmap(9E) uses the model parameter to describe the data model expected by the application. The model parameter is set to one of the following:

  • DDI_MODEL_ILP32 - The application uses the ILP32 data model

  • DDI_MODEL_LP64 - The application uses the LP64 data model

The model parameter can be passed untranslated to the ddi_model_convert_from(9F) routine or to STRUCT_INIT(). See "32-bit and 64-bit Data Structure Macros".

Data Sharing in mmap()

Because mmap(9E) does not have a parameter that can be used to pass data model information, the driver's mmap(9E) entry point can be written to use the new DDI function ddi_model_convert_from(9F). This function returns one of the following values to indicate the application's data type model:

  • DDI_MODEL_ILP32 - Application expects the ILP32 data model

  • DDI_MODEL_ILP64 - Application expects the LP64 data model

  • DDI_FAILURE - Function was not called from mmap(9E)

As with ioctl() and devmap(), the model bits can be passed to ddi_model_convert_from(9F) to determine whether data conversion is necessary, or the model can be handed to STRUCT_INIT().

Alternatively, migrate the device driver to support the devmap(9E) entry point.

 
 
 
  Previous   Contents   Next