static struct i2400m_work *__i2400m_work_setup( struct i2400m *i2400m, void (*fn)(struct work_struct *), gfp_t gfp_flags, const void *pl, size_t pl_size) { struct i2400m_work *iw; iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags); if (iw == NULL) return NULL; iw->i2400m = i2400m_get(i2400m); iw->pl_size = pl_size; memcpy(iw->pl, pl, pl_size); INIT_WORK(&iw->ws, fn); return iw; }
/* * TX an skb to an idle device * * When the device is in basestation-idle mode, we need to wake it up * and then TX. So we queue a work_struct for doing so. * * We need to get an extra ref for the skb (so it is not dropped), as * well as be careful not to queue more than one request (won't help * at all). If more than one request comes or there are errors, we * just drop the packets (see i2400m_hard_start_xmit()). */ static int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev, struct sk_buff *skb) { int result; struct device *dev = i2400m_dev(i2400m); unsigned long flags; d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); if (net_ratelimit()) { d_printf(3, dev, "WAKE&NETTX: " "skb %p sending %d bytes to radio\n", skb, skb->len); d_dump(4, dev, skb->data, skb->len); } /* We hold a ref count for i2400m and skb, so when * stopping() the device, we need to cancel that work * and if pending, release those resources. */ result = 0; spin_lock_irqsave(&i2400m->tx_lock, flags); if (!i2400m->wake_tx_skb) { netif_stop_queue(net_dev); i2400m_get(i2400m); i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */ i2400m_tx_prep_header(skb); result = schedule_work(&i2400m->wake_tx_ws); WARN_ON(result == 0); } spin_unlock_irqrestore(&i2400m->tx_lock, flags); if (result == 0) { /* Yes, this happens even if we stopped the * queue -- blame the queue disciplines that * queue without looking -- I guess there is a reason * for that. */ if (net_ratelimit()) d_printf(1, dev, "NETTX: device exiting idle, " "dropping skb %p, queue running %d\n", skb, netif_queue_stopped(net_dev)); result = -EBUSY; } d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); return result; }
/* * Schedule i2400m's specific work on the system's queue. * * Used for a few cases where we really need it; otherwise, identical * to i2400m_queue_work(). * * Returns < 0 errno code on error, 1 if ok. * * If it returns zero, something really bad happened, as it means the * works struct was already queued, but we have just allocated it, so * it should not happen. */ int i2400m_schedule_work(struct i2400m *i2400m, void (*fn)(struct work_struct *), gfp_t gfp_flags) { int result; struct i2400m_work *iw; BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw), gfp_flags); if (iw == NULL) goto error_kzalloc; iw->i2400m = i2400m_get(i2400m); INIT_WORK(&iw->ws, fn); result = schedule_work(&iw->ws); if (result == 0) result = -ENXIO; error_kzalloc: return result; }
/** * i2400m_queue_work - schedule work on a i2400m's queue * * @i2400m: device descriptor * * @fn: function to run to execute work. It gets passed a 'struct * work_struct' that is wrapped in a 'struct i2400m_work'. Once * done, you have to (1) i2400m_put(i2400m_work->i2400m) and then * (2) kfree(i2400m_work). * * @gfp_flags: GFP flags for memory allocation. * * @pl: pointer to a payload buffer that you want to pass to the _work * function. Use this to pack (for example) a struct with extra * arguments. * * @pl_size: size of the payload buffer. * * We do this quite often, so this just saves typing; allocate a * wrapper for a i2400m, get a ref to it, pack arguments and launch * the work. * * A usual workflow is: * * struct my_work_args { * void *something; * int whatever; * }; * ... * * struct my_work_args my_args = { * .something = FOO, * .whaetever = BLAH * }; * i2400m_queue_work(i2400m, 1, my_work_function, GFP_KERNEL, * &args, sizeof(args)) * * And now the work function can unpack the arguments and call the * real function (or do the job itself): * * static * void my_work_fn((struct work_struct *ws) * { * struct i2400m_work *iw = * container_of(ws, struct i2400m_work, ws); * struct my_work_args *my_args = (void *) iw->pl; * * my_work(iw->i2400m, my_args->something, my_args->whatevert); * } */ int i2400m_queue_work(struct i2400m *i2400m, void (*fn)(struct work_struct *), gfp_t gfp_flags, const void *pl, size_t pl_size) { int result; struct i2400m_work *iw; BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags); if (iw == NULL) goto error_kzalloc; iw->i2400m = i2400m_get(i2400m); memcpy(iw->pl, pl, pl_size); INIT_WORK(&iw->ws, fn); result = queue_work(i2400m->work_queue, &iw->ws); error_kzalloc: return result; }