Introduction #
In fields like industrial control, data acquisition, and communications, PCIe controllers from PLX (now part of Broadcom) are widely used. VxWorks 7, the latest real-time operating system from Wind River, introduces a modernized and modular driver framework called VxBus 2.0. This article walks through the process of developing a PCIe device driver for VxWorks 7 using a PLX controller such as the PLX8725, including practical code examples.
Overview of the VxBus 2.0 Driver Model #
VxBus is the official driver framework in VxWorks. VxBus 2.0, introduced in VxWorks 7, brings several improvements:
- Object-oriented and layered architecture
- Dynamic device plug-and-play support
- Better SMP (multi-core) support
- Compatibility with Flattened Device Tree (FDT)
A typical driver in VxBus 2.0 includes:
- A probe function to match supported devices
- An attach function to map hardware resources and register interrupts
- A detach function (optional) to release resources
- Public API functions for application interaction
About the PLX PCIe Controller (e.g., PLX8725) #
PLX PCIe switches and bridges, such as the PLX8725 or PLX8749, offer:
- Multiple BARs (Base Address Registers) for register mapping
- MSI/MSI-X interrupt support
- A built-in DMA engine
- Hot-plug capabilities and event signaling
These devices are typically detected and initialized via PCI configuration space in VxWorks.
Optional Device Tree Configuration #
When using Device Tree (FDT), a PCIe node can be described like this:
pcie@0x80000000 {
compatible = "plx,pcie8725";
reg = <0x80000000 0x1000>; // BAR region
interrupts = <32>; // IRQ number
};
In the driver, APIs such as vxbFdtDevGet() and vxbResourceAlloc() are used to retrieve these resources.
VxBus Driver Code Framework #
Header File: plxPcieDrv.h
#define PLX_VENDOR_ID 0x10B5
#define PLX_DEVICE_ID 0x8725
typedef struct {
VXB_DEV_ID dev;
void * barBase;
int irq;
VXB_RESOURCE * pResBar;
VXB_RESOURCE * pResIrq;
} PLX_PCIE_DRV_CTRL;
Driver Implementation: plxPcieDrv.c
LOCAL STATUS plxPcieProbe(VXB_DEV_ID dev) {
UINT16 vendorId, deviceId;
vxbPciConfigRead16(dev, PCI_CFG_VENDOR_ID, &vendorId);
vxbPciConfigRead16(dev, PCI_CFG_DEVICE_ID, &deviceId);
return (vendorId == PLX_VENDOR_ID && deviceId == PLX_DEVICE_ID) ? OK : ERROR;
}
LOCAL STATUS plxPcieAttach(VXB_DEV_ID dev) {
PLX_PCIE_DRV_CTRL *pCtrl = vxbMemAlloc(sizeof(*pCtrl));
if (!pCtrl) return ERROR;
pCtrl->dev = dev;
pCtrl->pResBar = vxbResourceAlloc(dev, VXB_RES_MEMORY, 0);
pCtrl->barBase = (void *)vxbResourceVirtAdrsGet(pCtrl->pResBar);
pCtrl->pResIrq = vxbResourceAlloc(dev, VXB_RES_IRQ, 0);
pCtrl->irq = (int)(long)vxbResourceAdrsGet(dev, VXB_RES_IRQ, 0);
vxbDevSoftcSet(dev, pCtrl);
vxbIntConnect(dev, pCtrl->pResIrq, plxPcieIsr, pCtrl);
vxbIntEnable(dev, pCtrl->pResIrq);
return OK;
}
LOCAL void plxPcieIsr(void *param) {
PLX_PCIE_DRV_CTRL *pCtrl = (PLX_PCIE_DRV_CTRL *)param;
UINT32 status = *(volatile UINT32 *)(pCtrl->barBase + 0x04);
*(volatile UINT32 *)(pCtrl->barBase + 0x04) = status;
// Custom interrupt handling here
}
Driver registration section:
LOCAL VXB_DRV plxPcieDrv = {
{NULL},
"plxPcie", "PLX PCIe Driver",
VXB_BUSID_PCI, 0, 0,
plxPcieProbe, plxPcieAttach, NULL
};
VXB_DRV_DEF(plxPcieDrv)
VXB_DRV_MOD_INSTALL(plxPcieDrv)
Debugging Tips #
- View PCI configuration:
-> vxbPciShow()
- List registered devices:
-> vxbDevShow()
- Print BAR and IRQ:
printf("BAR0 base: 0x%x, IRQ: %d\n", pCtrl->barBase, pCtrl->irq);
- Use
WindView
to trace interrupt latency
Recommended Extensions #
- Enable DMA transfer using vxbDma* interfaces
- Add user-space interface via ioctl or shared memory
- Support for hot-plug events and multiple BARs
Conclusion #
Combining VxWorks 7 with PLX PCIe controllers enables high-performance, real-time communication. With the modular VxBus 2.0 framework and Device Tree support, driver development becomes clean and scalable. This guide and starter code should serve as a strong foundation for your own PCIe driver development.