我正在使用Linux3.3,这是smsc911x的以太网驱动程序。我想把NAPI投票函数移到工作队列中。
我的问题是:
以下是一些解释:
当前的NAPI轮询功能直接读取recevie,这是我想要改变的,用DMA控制器来完成。对于这个DMA,我触发DMA,使用wait_event_interruptible睡觉,然后被DMA的ISR与wake_up_interruptible唤醒。如您所知,NAPI轮询功能处于中断上下文(softirq)中,因此我无法在那里睡觉以完成DMA。我希望将NAPI轮询函数(读取RX )移动到使用work_struct的等待队列(进程上下文)。
问题是,NAPI轮询函数是由内核使用两个参数调用的: struct napi_struct *napi和int预算。我希望将这些参数传递给work_struct,并将work_struct排队到工作队列(使用queue_work函数)。
work_struct看起来如下所示。(包括/linux/workQuee.h)
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};我认为atomic_long_t数据是用来将参数传递给work_struct的。如何将参数传递给work_struct?我尝试过这样做(我在用于设备驱动程序struct smsc911x_data的结构中添加了用于传递工作的成员struct work_struct rx_work ):
struct work_arg { // a new struct for pass the arguments
struct napi_struct *napi;
int budget;
};
/* NAPI poll function */
static int smsc911x_poll(struct napi_struct *napi, int budget) {
struct smsc911x_data *pdata =
container_of(napi, struct smsc911x_data, napi);
struct net_device *dev = pdata->dev;
int npackets = 0;
if (enable_rx_use_dma == 1) { // when using DMA for FIFO read
prom_printf("moving it to workqueue\n");
struct work_arg *p;
p = kzalloc(sizeof(struct work_arg), GFP_KERNEL);
p->napi = napi;
p->budget = budget;
pdata->rx_work.data = (atomic_long_t) p; // <== THIS LINE
prom_printf("queue work, with napi = %x, budget = %d\n", napi, budget);
queue_work(rx_work_workqueue, &pdata->rx_work); // smsc911x_poll_work } else {
-- original NAP poll function, reads FIFO until it's empty and enables the RX interrupt and
-- keeps the number of processed packets to npackets.
return npackets;
}对于上面的“此行”,我在编译过程中会出错。
with pdata->rx_work.data = p; , I get error: incompatible types when assigning to type 'atomic_long_t' from type 'struct work_arg *'
with pdata->rx_work.data = (atomic_long_t) p; , I get error: conversion to non-scalar type requested.此外,在新的工作函数中,如何提取原始论证?我在下面试了一下,这会给我带来错误。
/* New work function called by the default worker thread */ static int smsc911x_poll_work(struct work_struct *work) {
struct smsc911x_data *pdata =
container_of(work, struct smsc911x_data, rx_work);
struct net_device *dev = pdata->dev;
int npackets = 0;
struct napi_struct *napi = (struct work_struct *)work->data.napi; // <== THIS LINE
int budget = (struct work_struct *)work->data.budget; // <== THIS LINE ..
}从上面的“这句话,我会犯错误”。
错误:“atomic_long_t”没有成员名为“napi”错误:“atomic_long_t”没有名为“预算”的成员
我不知道如何将返回值传递给原始的NAPI投票函数调用者。
我不确定这种转换(从NAPI投票到工作队列)是否可行。很抱歉有这么长的问题,但是如果有任何帮助,我们将不胜感激。
添加:因为struct smsc911x_data同时具有struct work_struct rx_work和struct work_struct rx_work;作为成员,我可以通过以下方法轻松地从work_struct *work (工作函数的参数)中获得struct *rx_work:
struct smsc911x_data *pdata = container_of(work,struct smsc911x_data,rx_work);struct napi_struct *pdata= &pdata.napi;
所以,也许我可以在struct smsc911x_data中通过一个新的成员值来传递int预算。我很想知道这个案子的正确做法。
发布于 2015-06-08 09:18:06
只需创建新结构,该结构嵌入work_struct并将参数添加到其中:
struct my_work {
struct work_struct base_work;// Embedded work_struct
struct napi_struct *napi; // Your arguments
int budget;
};
static int smsc911x_poll(struct napi_struct *napi, int budget) {
struct my_work* p = kmalloc(sizeof(*p), GFP_ATOMIC /* Flag usable for interrupt context */);
INIT_WORK(&p->base_work, smsc911x_poll_work); // Initialize underliying structure.
p->budget = budget; // Initialize your members
p->napi = napi;
...
}使用container_of
static int smsc911x_poll_work(struct work_struct *work) {
struct my_work* p = container_of(work, struct my_work, base_work);
...
}正如我从描述(例如,http://www.linuxfoundation.org/collaborate/workgroups/networking/napi)中了解到的那样,这个函数应该处理已准备好的数据包。这个处理应该在函数本身内完成,而不是推迟到workqueue或类似的。
发布于 2018-10-23 11:36:08
这种方法看起来非常无效,因为您需要两次中断,一次是在接收数据包时,另一次是在DMA tansfer完成时。
我认为这是DMA网络接口的工作方式:当数据包到达时,套接字缓冲区已经被分配并映射到DMA内存缓冲区中,DMA被启动。
sk_buff传递到上层,并初始化新的DMA缓冲区。如果处理了所有数据包(配额),则启用IRQ,并通知NAPI停止轮询。https://stackoverflow.com/questions/30704408
复制相似问题