4. 实现网络接口驱动
任务目标
为PowerPC目标板上的板载以太网控制器(以Intel 82559/82551为例,PCI接口)编写VxWorks网络驱动,使目标板能够通过TFTP从主机下载VxWorks镜像并启动。本案例聚焦于驱动核心的注册、收发路径与中断处理,确保tftp命令可用。
环境与依赖
- VxWorks 5.5/6.x(BSP开发环境),Tornado或Workbench
- PowerPC目标板(PCI总线,板载Intel PRO/100系列网卡)
- 主机TFTP服务器(IP:192.168.1.100,镜像文件
vxWorks) - 目标板IP规划:192.168.1.50
驱动实现要点
本驱动基于VxWorks END(Enhanced Network Driver)模型,核心工作包括:PCI设备探测与寄存器映射、描述符环初始化、中断服务程序(ISR)对接、以及endDevInit回调实现。驱动通过pciConfigInLong读取BAR地址完成MMIO映射,收发采用环形描述符(每个描述符对应一个缓冲块)。
关键完整代码
/* endDev.c - Intel 82559 END driver for VxWorks (PowerPC) */
#include <vxWorks.h>
#include <end.h>
#include <pci.h>
#include <intLib.h>
#include <netBufLib.h>
/* 寄存器偏移 */
#define CSR_CMD 0x0000
#define CSR_STATUS 0x0004
#define CSR_TPT 0x0038 /* 发送描述符尾 */
#define CSR_RDT 0x0028 /* 接收描述符尾 */
#define CSR_IMASK 0x00D0
/* 描述符结构(简化) */
typedef struct {
UINT32 status;
UINT32 cmd;
UINT32 link;
UINT32 bufAddr;
} DESC;
#define NUM_TX_DESC 16
#define NUM_RX_DESC 16
#define PKT_BUF_SIZE 2048
typedef struct {
DESC txDesc[NUM_TX_DESC];
DESC rxDesc[NUM_RX_DESC];
char *txBuf[NUM_TX_DESC];
char *rxBuf[NUM_RX_DESC];
int txHead, txTail;
int rxHead, rxTail;
volatile UINT32 *regs;
END_OBJ end;
} I82559_DEV;
static I82559_DEV i82559;
/* 中断处理 */
static void i82559Isr(void *arg)
{
I82559_DEV *dev = (I82559_DEV *)arg;
UINT32 status = dev->regs[CSR_STATUS/4];
if (status & 0x01) { /* RUS: 接收单元已停止或空闲 */
/* 处理接收包 */
while (dev->rxDesc[dev->rxTail].status & 0x8000) {
int len = dev->rxDesc[dev->rxTail].status & 0x3FFF;
END_OBJ *pEnd = &dev->end;
M_BLK_ID pMblk = netBufLibAlloc(dev->rxBuf[dev->rxTail], len);
if (pMblk) {
pEnd->pReceiveRtn(pEnd, pMblk);
}
dev->rxDesc[dev->rxTail].status = 0;
dev->rxTail = (dev->rxTail + 1) % NUM_RX_DESC;
dev->regs[CSR_RDT/4] = dev->rxTail;
}
}
if (status & 0x02) { /* TUS: 发送完成 */
dev->txHead = (dev->txHead + 1) % NUM_TX_DESC;
}
}
/* 发送包 */
static int i82559Send(END_OBJ *pEnd, M_BLK_ID pMblk)
{
I82559_DEV *dev = (I82559_DEV *)pEnd->pDevice;
int len = pMblk->mLen;
char *buf = (char *)pMblk->mData;
int idx = dev->txHead;
if (dev->txDesc[idx].status & 0x8000) return ERROR; /* 描述符忙 */
memcpy(dev->txBuf[idx], buf, len);
dev->txDesc[idx].bufAddr = (UINT32)dev->txBuf[idx];
dev->txDesc[idx].cmd = len | 0x01000000; /* 发送+中断 */
dev->txDesc[idx].status = 0x8000;
dev->regs[CSR_TPT/4] = idx;
return OK;
}
/* 设备初始化 */
static STATUS i82559Init(END_OBJ *pEnd)
{
I82559_DEV *dev = (I82559_DEV *)pEnd->pDevice;
int i;
/* 复位网卡 */
dev->regs[CSR_CMD/4] = 0x8000; /* 软件复位 */
taskDelay(1);
dev->regs[CSR_CMD/4] = 0x0000;
/* 初始化RX描述符 */
for (i = 0; i < NUM_RX_DESC; i++) {
dev->rxBuf[i] = (char *)memalign(8, PKT_BUF_SIZE);
dev->rxDesc[i].bufAddr = (UINT32)dev->rxBuf[i];
dev->rxDesc[i].status = 0x8000; /* 就绪 */
}
dev->rxHead = dev->rxTail = 0;
dev->regs[CSR_RDT/4] = NUM_RX_DESC - 1;
/* 使能中断 */
dev->regs[CSR_IMASK/4] = 0x0003; /* RUS+TUS */
intConnect(INUM_TO_IVEC(pEnd->pDevContext->intNum), i82559Isr, dev);
intEnable(pEnd->pDevContext->intNum);
return OK;
}
/* END设备创建 */
END_OBJ *i82559EndCreate(int unit, char *pName, void *pBSP)
{
I82559_DEV *dev = &i82559;
UINT32 bar0, bar1;
int pciBus, pciDev, pciFunc;
/* 查找PCI设备(Vendor 0x8086, Device 0x1229) */
if (pciFindDevice(0x8086, 0x1229, 0, &pciBus, &pciDev, &pciFunc) != OK)
return NULL;
pciConfigInLong(pciBus, pciDev, pciFunc, PCI_CFG_BASE_ADDRESS_0, &bar0);
pciConfigInLong(pciBus, pciDev, pciFunc, PCI_CFG_BASE_ADDRESS_1, &bar1);
dev->regs = (volatile UINT32 *)(bar0 & 0xFFFFFFF0);
/* 注册END对象 */
dev->end.pDevice = dev;
dev->end.pInit = i82559Init;
dev->end.pSend = i82559Send;
dev->end.pDevContext = (void *)pBSP;
return &dev->end;
}
BSP集成配置
/* configNet.h 中添加 */
#define INCLUDE_END
#define I82559_LOAD_FUNC i82559EndCreate
#define I82559_LOAD_STRING "0,0:0"
运行与验证
- 将
endDev.c编译链接到VxWorks镜像,确保INCLUDE_END和INCLUDE_TFTP已定义。 - 启动目标板,在shell中执行:
ipAttach("i82559", "0", "192.168.1.50", "255.255.255.0") - 测试网络连通性:
预期输出包含ping "192.168.1.100"icmpEchoRequest的回复确认。 - 执行TFTP下载:
tftp "192.168.1.100", "vxWorks", "0x100000"
通过条件:TFTP命令返回value = 0,且内存地址0x100000处可观察到有效镜像数据(前几个字节为0x00 0x00 0x00 0x00或PowerPC异常向量)。若ping不通,检查PCI设备枚举是否成功(pciFindDevice返回值)及中断号配置。
常见问题
- PCI设备未找到:确认板载网卡为Intel 82559/82551,或修改
pciFindDevice中的Vendor/Device ID。 - 中断不触发:检查BSP中
sysIntNum映射,确保PCI中断线正确连接。 - 收发超时:增大
PKT_BUF_SIZE或检查描述符环是否溢出(观察CSR_STATUS的RNR/TNO位)。