how to offload NAPI poll function to workqueue
Chan Kim
ckim at etri.re.kr
Mon Jun 8 03:26:44 EDT 2015
Oh, I just realized that at the entrance of the work function,
I can easily obtain the struct napi *napi from work_struct *work by :
(because struct smsc911x_data has both struct napi napi; and struct work_struct rx_work; as members)
struct smsc911x_data *pdata =
container_of(work, struct smsc911x_data, rx_work);
struct napi_struct *napi = &pdata.napi;
so maybe I can just pass the int budget through a new member value in struct smsc911x_data.
Has anyone done similar thing before?
Chan
보낸 사람 : "Chan Kim" <ckim at etri.re.kr>
보낸 날짜 : 2015-06-08 16:06:59 ( +09:00 )
받는 사람 : kernelnewbies at kernelnewbies.org <kernelnewbies at kernelnewbies.org>
참조 :
제목 : how to offload NAPI poll function to workqueue
Hello,
I'm working with linux ver 3.3, Ethernet driver for smsc911x. Current NAPI poll function reads recevie FIFO directly which I want to do with DMA controller. For this DMA, I trigger DMA, sleep with wait_event_interruptible, and get woken up by DMA's ISR with wake_up_interruptible. As you know, NAPI poll function is in interrupt context (softirq) so I cannot sleep there for DMA completion. I want to move the NAPI poll function(reading RX FIFO) to waitqueue(process context) usnig a work_struct.
The problem is, NAPI poll function is called by the kernel with two arguments : struct napi_struct *napi and int budget.
I want to pass those argument to the work_struct and queue the work_struct to the workqueue (using queue_work function).
the work_struct looks like below. (include/linux/workqueue.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
};
I take that atomic_long_t data is for passing the argument to the work_struct. how can I pass the arguments to the work_struct?
I tried this (I added in the structure for device driver struct smsc911x_data a member struct work_struct rx_work for passing the 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;
}
For "THIS LINE" above, I'm getting error during compile.
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.
Also, in the new work function, How can I extract the original argments? I tried this below which gives me errors.
/* 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
..
}
>From the above 'THIS LINE's, I get erros below.
error: 'atomic_long_t' has no member named 'napi'
error: 'atomic_long_t' has no member named 'budget'
and I don't know how to pass the return value to the original NAPI poll functino caller.
So my questions are :
1. How do I pass the NAPI poll function arguments to the work_struct?
2. How can I get the NAPI poll functino arguments back from the work_struct? (related to Q.1)
3. How can I return the npackets value to the original NAPI poll function caller?
I'm not sure if this kind of conversion (from NAPI poll to workqueue) is possible.
Sorry for the long questions but any help will be greatly appreciated.
Thanks,
Chan
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies at kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
More information about the Kernelnewbies
mailing list