编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

GLDv2 入口点

入口点必须通过针对使用 GLDv2 的接口设计的特定于设备的网络驱动程序实现。

gld_mac_info(9S) 结构是用于在特定于设备的驱动程序与 GLDv2 模块之间进行通信的主结构。请参见 gld(7D) 手册页。此结构中的某些元素是指向此处所述的入口点的函数指针。特定于设备的驱动程序必须在调用 gld_register() 之前在其 attach(9E) 例程中初始化这些函数指针。

gldm_reset() 入口点

int prefix_reset(gld_mac_info_t *macinfo);

gldm_reset() 可将硬件重置为初始状态。

gldm_start() 入口点

int prefix_start(gld_mac_info_t *macinfo);

gldm_start() 可使设备生成中断。gldm_start() 还可使驱动程序调用 gld_recv(),从而将已接收的数据包传送到 GLDv2。

gldm_stop() 入口点

int prefix_stop(gld_mac_info_t *macinfo);

gldm_stop() 禁止设备生成任何中断,并阻止驱动程序为将数据包传送到 GLDv2 而调用 gld_recv()。GLDv2 依赖 gldm_stop() 例程来确保设备不再中断。gldm_stop() 必须成功执行此操作。此函数应该始终返回 GLD_SUCCESS

gldm_set_mac_addr() 入口点

int prefix_set_mac_addr(gld_mac_info_t *macinfo, unsigned char *macaddr);

gldm_set_mac_addr() 可设置硬件用于接收数据的物理地址。利用此函数,可通过已传递的 MAC 地址 macaddr 对设备进行编程。如果当前没有足够的资源来执行请求,则 gldm_set_mac_add() 应该返回 GLD_NORESOURCES。如果不支持所请求的函数,则 gldm_set_mac_add() 应该返回 GLD_NOTSUPPORTED。

gldm_set_multicast() 入口点

int prefix_set_multicast(gld_mac_info_t *macinfo, 
     unsigned char *multicastaddr, int multiflag);

gldm_set_multicast() 可启用和禁用设备级别的特定多播地址接收。如果将第三个参数 multiflag 设置为 GLD_MULTI_ENABLE,则 gldm_set_multicast() 会将接口设置为使用多播地址接收包。gldm_set_multicast() 将使用第二个参数所指向的多播地址。如果将 multiflag 设置为 GLD_MULTI_DISABLE,则允许驱动程序禁用指定的多播地址接收。

当 GLDv2 要启用或禁用多播、组或功能地址 (functional address) 接收时,便会调用此函数。GLDv2 不会做出有关设备如何支持多播并调用此函数以启用或禁用特定多播地址的假设。某些设备可能会使用散列算法和位掩码来启用多播地址集合。将允许此过程,并且 GLDv2 会过滤出所有多余的包。如果在设备级别禁用一个地址会导致禁用多个地址,则设备驱动程序应该保留所有必要信息。此方法可避免禁用 GLDv2 已启用但未禁用的地址。

不能调用 gldm_set_multicast() 来启用已启用的特定多播地址。同样,也不能调用 gldm_set_multicast() 来禁用当前未启用的地址。GLDv2 将跟踪针对同一多播地址发出的多个请求。GLDv2 仅在第一次请求启用特定多播地址或最后一次请求禁用特定多播地址时才调用驱动程序的入口点。如果当前没有足够的资源来执行请求,则函数应该返回 GLD_NORESOURCES。如果不支持所请求的函数,则函数应该返回 GLD_NOTSUPPORTED。

gldm_set_promiscuous() 入口点

int prefix_set_promiscuous(gld_mac_info_t *macinfo, int promiscflag);

gldm_set_promiscuous() 可启用和禁用混杂模式。当 GLDv2 要启用或禁用介质上的所有包接收时,便会调用此函数。还可以将此函数限制为针对介质上的多播包使用。如果将第二个参数 promiscflag 设置为 GLD_MAC_PROMISC_PHYS 的值,则函数会启用物理级别的混杂模式。物理级别的混杂模式会导致接收介质上的所有包。如果将 promiscflag 设置为 GLD_MAC_PROMISC_MULTI,则会启用所有多播包接收。如果将 promiscflag 设置为 GLD_MAC_PROMISC_NONE,则会禁用混杂模式。

在混杂多播模式下,无仅限多播混杂模式的设备的驱动程序必须将设备设置为物理混杂模式。此方法可确保接收所有多播包。在这种情况下,例程应该返回 GLD_SUCCESS。GLDv2 软件会过滤出所有多余的包。如果当前没有足够的资源来执行请求,则函数应该返回 GLD_NORESOURCES。如果不支持所请求的函数,gld_set_promiscuous() 函数应该返回 GLD_NOTSUPPORTED

为了向前兼容,gldm_set_promiscuous() 例程应该处理所有 promiscflag 无法识别的值,如同这些值为 GLD_MAC_PROMISC_PHYS 一样。

gldm_send() 入口点

int prefix_send(gld_mac_info_t *macinfo, mblk_t *mp);

gldm_send() 可将要发送到设备的包进行排队以进行传输。将向此例程传递包含要发送的包的 STREAMS 消息。此消息可能包括多个消息块。send() 例程必须遍历消息中的所有消息块,以访问要发送的整个包。应对驱动程序进行适当设置,以便处理并跳过链表中所有零长度的消息连续块。驱动程序还应该检查包是否未超过最大允许包大小。如有必要,驱动程序必须将包填充到最小允许包大小。如果发送例程成功传输包或对包排队,则应该返回 GLD_SUCCESS

如果无法立即接受要传输的包,则发送例程应该返回 GLD_NORESOURCES。在这种情况下,GLDv2 会稍后重试。如果 gldm_send() 曾经返回 GLD_NORESOURCES,则驱动程序必须在稍后资源可用时调用 gld_sched()。此 gld_sched() 调用会通知 GLDv2 重试驱动程序先前无法对其进行排队以进行传输的包。(如果调用驱动程序的 gldm_stop() 例程,则会为驱动程序免除这种职责,直到驱动程序从 gldm_send() 例程返回 GLD_NORESOURCES 为止。不过,再次调用 gld_sched() 也不会导致错误操作。)

如果驱动程序的发送例程返回 GLD_SUCCESS,则驱动程序会负责释放不再需要的消息。如果硬件使用 DMA 直接读取数据,则驱动程序在硬件完全读取数据之前不得释放消息。在这种情况下,驱动程序可以释放中断例程中的消息。或者,驱动程序可以在将来发送操作的开始回收缓冲区。如果发送例程返回 GLD_SUCCESS 之外的任何内容,则驱动程序不得释放消息。如果在不存在到网络或链路伙伴的物理连接时调用 gldm_send(),则会返回 GLD_NOLINK

gldm_intr() 入口点

int prefix_intr(gld_mac_info_t *macinfo);

当设备可能已中断时,便会调用 gldm_intr()。由于其他设备可以共享中断,因此,驱动程序必须检查设备状态以确定此设备是否实际导致了中断。如果驱动程序所控制的设备并未导致中断,则此例程必须返回 DDI_INTR_UNCLAIMED。否则,驱动程序必须修复中断并返回 DDI_INTR_CLAIMED。如果中断由成功接收包导致,则此例程应该将已接收的包放入类型为 M_DATA 的 STREAMS 消息中,并将此消息传递给 gld_recv()

gld_recv() 将传入包向上游传递到网络协议栈的相应下一层。在调用 gld_recv 之前,此例程必须正确设置 STREAMS 消息的 b_rptrb_wptr() 成员。

在调用 gld_recv() 期间,驱动程序应该避免持有互斥锁或其他锁。需要特别指出的是,在调用 gld_recv() 期间,不得持有传输线程可使用的锁。在某些情况下,调用 gld_recv() 的中断线程可发送传出包,这会导致调用驱动程序的 gldm_send() 例程。如果在调用 gld_recv()gldm_send() 尝试获取 gldm_intr() 持有的互斥锁,则会由于存在递归互斥锁入口操作而出现紧急情况。在调用 gld_recv() 时,如果其他驱动程序入口点尝试获取驱动程序所持有的互斥锁,则会导致死锁。

中断代码应该针对所有错误递增统计计数器。这些错误包括分配已接收数据所需的缓冲区时出现的故障,以及所有特定于硬件的错误(如 CRC 错误或帧错误)。

gldm_get_stats() 入口点

int prefix_get_stats(gld_mac_info_t *macinfo, struct gld_stats *stats);

gldm_get_stats() 可收集硬件和/或驱动程序专用计数器的统计信息,并更新 stats 所指向的 gld_stats(9S) 结构。GLDv2 会针对统计信息请求调用此例程。GLDv2 会使用 gldm_get_stats() 机制从驱动程序获取与设备有关的统计信息,然后再编写统计信息请求回复。有关已定义的统计计数器的更多信息,请参见 gld_stats(9S)gld(7D)qreply(9F) 手册页。

gldm_ioctl() 入口点

int prefix_ioctl(gld_mac_info_t *macinfo, queue_t *q, mblk_t *mp);

gldm_ioctl() 可实现所有特定于设备的 ioctl 命令。如果驱动程序未实现任何 ioctl 函数,则允许此元素为 null。驱动程序负责在返回 GLD_SUCCESS 之前将消息块转换为 ioctl 回复消息,并调用 qreply(9F) 函数。此函数应该始终返回 GLD_SUCCESS。驱动程序应该根据需要报告要传递给 qreply(9F) 的消息中的所有错误。如果将 gldm_ioctl 元素指定为 NULL,则 GLDv2 会返回类型为 M_IOCNAK 的消息以及 EINVAL 错误。