Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac53aed9 authored by Inaky Perez-Gonzalez's avatar Inaky Perez-Gonzalez
Browse files

wimax/i2400m: on device stop, clean up pending wake & TX work



When the i2400m device needs to wake up an idle WiMAX connection, it
schedules a workqueue job to do it.

Currently, only when the network stack called the _stop() method this
work struct was being cancelled. This has to be done every time the
device is stopped.

So add a call in i2400m_dev_stop() to take care of such cleanup, which
is now wrapped in i2400m_net_wake_stop().

Signed-off-by: default avatarInaky Perez-Gonzalez <inaky@linux.intel.com>
parent cb5b756f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -527,6 +527,7 @@ void __i2400m_dev_stop(struct i2400m *i2400m)

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
	wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
	i2400m_net_wake_stop(i2400m);
	i2400m_dev_shutdown(i2400m);
	i2400m->ready = 0;
	i2400m->bus_dev_stop(i2400m);
+1 −0
Original line number Diff line number Diff line
@@ -691,6 +691,7 @@ extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
			  const void *, int);
extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
			   enum i2400m_cs);
extern void i2400m_net_wake_stop(struct i2400m *);
enum i2400m_pt;
extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);

+33 −20
Original line number Diff line number Diff line
@@ -113,11 +113,6 @@ int i2400m_open(struct net_device *net_dev)
}


/*
 *
 * On kernel versions where cancel_work_sync() didn't return anything,
 * we rely on wake_tx_skb() being non-NULL.
 */
static
int i2400m_stop(struct net_device *net_dev)
{
@@ -125,21 +120,7 @@ int i2400m_stop(struct net_device *net_dev)
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
	/* See i2400m_hard_start_xmit(), references are taken there
	 * and here we release them if the work was still
	 * pending. Note we can't differentiate work not pending vs
	 * never scheduled, so the NULL check does that. */
	if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
	    && i2400m->wake_tx_skb != NULL) {
		unsigned long flags;
		struct sk_buff *wake_tx_skb;
		spin_lock_irqsave(&i2400m->tx_lock, flags);
		wake_tx_skb = i2400m->wake_tx_skb;	/* compat help */
		i2400m->wake_tx_skb = NULL;	/* compat help */
		spin_unlock_irqrestore(&i2400m->tx_lock, flags);
		i2400m_put(i2400m);
		kfree_skb(wake_tx_skb);
	}
	i2400m_net_wake_stop(i2400m);
	d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m);
	return 0;
}
@@ -230,6 +211,38 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
}



/*
 * Cleanup resources acquired during i2400m_net_wake_tx()
 *
 * This is called by __i2400m_dev_stop and means we have to make sure
 * the workqueue is flushed from any pending work.
 */
void i2400m_net_wake_stop(struct i2400m *i2400m)
{
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
	/* See i2400m_hard_start_xmit(), references are taken there
	 * and here we release them if the work was still
	 * pending. Note we can't differentiate work not pending vs
	 * never scheduled, so the NULL check does that. */
	if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
	    && i2400m->wake_tx_skb != NULL) {
		unsigned long flags;
		struct sk_buff *wake_tx_skb;
		spin_lock_irqsave(&i2400m->tx_lock, flags);
		wake_tx_skb = i2400m->wake_tx_skb;	/* compat help */
		i2400m->wake_tx_skb = NULL;	/* compat help */
		spin_unlock_irqrestore(&i2400m->tx_lock, flags);
		i2400m_put(i2400m);
		kfree_skb(wake_tx_skb);
	}
	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
	return;
}


/*
 * TX an skb to an idle device
 *