Documentation

PCI Bus Drivers

Introduction

When writing Simulink® Real-Time™ drivers for PCI devices, consider the memory access method. A PCI device can be either I/O port mapped or memory mapped.

  • I/O port mapped — The BIOS assigns a port range.

  • Memory mapped — The BIOS assigns a memory region.

The target computer BIOS automatically assigns a conflict-free set of resources to the PCI devices found in the system when the system starts. You typically do not know where the board resides (base address) before driver initialization. However, you can obtain this information by querying the PCI configuration space at run time with functions that the Simulink Real-Time software provides.

To locate a PCI device, you need the following:

  • Vendor and device ID

  • Slot number or bus and slot number

  • Optionally, subsystem vendor and subsystem device ID (if the vendor and device ID do not uniquely identify the board).

You can have the drivers locate PCI devices in one of the following ways:

  • If the system has one board of a given type, set the driver slot option to -1. With this setting, the driver searches for the first board that matches a vendor and device ID.

  • If the system contains multiple boards of the same type, setting the slot option to -1 does not find the additional boards. In that case, specify the bus and slot numbers with the vendor and device IDs.

PCI Configuration Space API

To access a PCI device, locate the board in target computer memory. To locate the board, access the configuration space. This space contains relevant board information, such as the base address and the access type (I/O port or memory mapped). You can access this space with functions that the Simulink Real-Time software provides.

  • Vendor and device ID — The driver searches the boards for the specified vendor (manufacturer) and device ID. The PCI Steering Committee, an independent standards body, assigns a unique vendor ID (uint16) to each PCI board vendor. Each vendor then assigns a unique ID to each PCI board type it supports.

    Note

    Vendor and device IDs do not uniquely identify a board. For example, boards that use the PLX-9080 bus interface chip have a vendor ID of 10B5 (the vendor ID assigned to PLX Technology, Inc.). The device ID for the chip is 9080. To specify a particular board that contains this chip, use a subvendor and subdevice ID in addition to the vendor and device IDs.

  • Slot number or bus and slot number — The driver looks only for the board that matches the specified vendor and device ID and slot number.

PCI Device Information

Use the xpcGetPCIDeviceInfo function to get information for a PCI device in your system. The syntax for this function is:

int xpcGetPCIDeviceInfo (uint16_T vendorId, uint16_T deviceId, uint16_T subVendorId, uint16_T subDeviceId, uint16_T bus, uint16_T slot, xpcPCIDevice *pciInfo);

This function returns the xpcPCIDevice structure filled according to the following:

If You Supply...This Function....

All four parameters

Looks for a device that matches all four parameters and returns the xpcPCIDevice structure for that device. Use this form if your system has multiple boards from the same vendor with the same ID and you want to specify the exact device.

XPC_NO_SUB for the subVendorId or subDeviceId parameter

Does not consider the subvendor or subdevice ID when looking for a match for the specified device. It returns the xpcPCIDevice structure for a device that matches the other parameters. You can use this form if you do not plan to use the subVendorId or subDeviceId values.

XPC_NO_BUS_SLOT for the slot for the device

Returns the first PCI device it finds that matches the remaining parameters. You can use this form if you know that your system has only one board with a particular ID set.

Passing Slot Information from Block Mask to Driver

Simulink Real-Time drivers use the following conventions to fill in slot parameters and retrieve slot information. Use the convention that works best for you.

Set...To...

Set slot = -1

To find the first instance of the board, assume bus = 0 and call the xpcGetPCIDeviceInfo function.

Set slot = S

To find the specified board, assume bus = 0 and call the xpcGetPCIDeviceInfo function. If the board matches the IDs, return the PCI information to the driver. Otherwise, return an error.

Set slot = [B, S]

Check bus B and slot S for the specified board. If the board matches the IDs, return the PCI information to the driver. Otherwise, return an error.

Setting slot = [0, S] is identical to slot = S.

The following example shows how to use xpcGetPCIDeviceInfo to program the driver to accept slot number input or slot and bus number input from the driver block.

  1. Call this function from the mdlStart callback function.

  2. Pass the slot number or slot and bus number into the xpcGetPCIDeviceInfo function using code like the following:

    uint16_T       vendorId, deviceId;
    int32_T        bus, slot, subvendor, subdevice;
    xpcPCIDevice   pciInfo;
    
    /* S_PCI_SLOT_ARG is passed in from the mask */
    /* Typically the slot arg is a scalar containing -1 if the target 
    has only one board of this type */
    /* If the target has multiple boards of this typem, the slot arg 
    is a vector containing bus and slot info */
    /* This code snipped parses the slot arg into bus and slot */
    if ( (int_T)(mxGetN(ssGetSFcnParam(S, S_PCI_SLOT_ARG))) == 1 ) {
    	bus  = 0;
    	slot = (int32_T)(mxGetPr(ssGetSFcnParam(S, S_PCI_SLOT_ARG))[0]);
    } else {
    	bus  = (int32_T)(mxGetPr(ssGetSFcnParam(S, S_PCI_SLOT_ARG))[0]);
    	slot = (int32_T)(mxGetPr(ssGetSFcnParam(S, S_PCI_SLOT_ARG))[1]);
    }
    
    vendorId = (uint16_T)0x1234;
    deviceId = (uint16_T)0x9876;
    subvendor = (uint16_T)0x5678;
    subdevice = (uint16_T)0x8765;
    /* Set subvendor and subdevice to XPC_NO_SUB, XPC_NO_SUB if they are not required */
    
    /* xpcGetPCIDeviceInfo() populates the pciInfo struct */
    if ( xpcGetPCIDeviceInfo(vendorId, deviceId,
    					subvendor, subdevice,
    					bus, slot,
    					&pciInfo) ) {
    	sprintf(msg, "Board 0x%x not found at bus %d slot %d", deviceId, bus, slot);
    	ssSetErrorStatus(S, msg);
    	return;
    }

For detailed information on the xpcPCIDevice structure, see xpcPCIDevice.

Memory-Mapped Accesses

A memory-mapped PCI board uses up to six memory regions to access board regions and memory. Each region can have a different length. Call the xpcReserveMemoryRegion function for each PCI memory region you want to access. Use the returned virtual address to access the region. Failure to use the virtual address can cause a segmentation fault.

To access a memory mapped location, do the following:

  1. Declare a variable of the required pointer type to hold the memory location. For example:

    volatile uint32 *csr; /* Control and status register */

    Note

    Use the volatile keyword here; otherwise, the compiler can optimize away accesses to this location.

  2. Set the pointer value (address) to the physical address at which the register resides.

I/O Port Accesses

To access I/O ports, use the following functions:

Sample PCI Device Driver

To access example PCI device driver code, type:

cd(fullfile(matlabroot,'toolbox','rtw','targets','xpc','target','build','xpcblocks'));

This folder contains driver code for boards supported by Simulink Real-Time.

Note

To specify the S-function name for an S-Function block, enter the C file name without the extension.

Was this topic helpful?