net/mvpp2: Replace tasklet with softirq hrtimer
The tx_done_tasklet tasklet is used in invoke the hrtimer (mvpp2_hr_timer_cb) in softirq context. This can be also achieved without the tasklet but with HRTIMER_MODE_SOFT as hrtimer mode. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
03eb57bb89
commit
ecb9f80db2
@@ -829,9 +829,8 @@ struct mvpp2_pcpu_stats {
|
|||||||
/* Per-CPU port control */
|
/* Per-CPU port control */
|
||||||
struct mvpp2_port_pcpu {
|
struct mvpp2_port_pcpu {
|
||||||
struct hrtimer tx_done_timer;
|
struct hrtimer tx_done_timer;
|
||||||
|
struct net_device *dev;
|
||||||
bool timer_scheduled;
|
bool timer_scheduled;
|
||||||
/* Tasklet for egress finalization */
|
|
||||||
struct tasklet_struct tx_done_tasklet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mvpp2_queue_vector {
|
struct mvpp2_queue_vector {
|
||||||
|
@@ -2651,31 +2651,21 @@ handled:
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu)
|
static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
ktime_t interval;
|
struct net_device *dev;
|
||||||
|
struct mvpp2_port *port;
|
||||||
if (!port_pcpu->timer_scheduled) {
|
|
||||||
port_pcpu->timer_scheduled = true;
|
|
||||||
interval = MVPP2_TXDONE_HRTIMER_PERIOD_NS;
|
|
||||||
hrtimer_start(&port_pcpu->tx_done_timer, interval,
|
|
||||||
HRTIMER_MODE_REL_PINNED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mvpp2_tx_proc_cb(unsigned long data)
|
|
||||||
{
|
|
||||||
struct net_device *dev = (struct net_device *)data;
|
|
||||||
struct mvpp2_port *port = netdev_priv(dev);
|
|
||||||
struct mvpp2_port_pcpu *port_pcpu;
|
struct mvpp2_port_pcpu *port_pcpu;
|
||||||
unsigned int tx_todo, cause;
|
unsigned int tx_todo, cause;
|
||||||
|
|
||||||
port_pcpu = per_cpu_ptr(port->pcpu,
|
port_pcpu = container_of(timer, struct mvpp2_port_pcpu, tx_done_timer);
|
||||||
mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
|
dev = port_pcpu->dev;
|
||||||
|
|
||||||
if (!netif_running(dev))
|
if (!netif_running(dev))
|
||||||
return;
|
return HRTIMER_NORESTART;
|
||||||
|
|
||||||
port_pcpu->timer_scheduled = false;
|
port_pcpu->timer_scheduled = false;
|
||||||
|
port = netdev_priv(dev);
|
||||||
|
|
||||||
/* Process all the Tx queues */
|
/* Process all the Tx queues */
|
||||||
cause = (1 << port->ntxqs) - 1;
|
cause = (1 << port->ntxqs) - 1;
|
||||||
@@ -2683,18 +2673,13 @@ static void mvpp2_tx_proc_cb(unsigned long data)
|
|||||||
mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
|
mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
|
||||||
|
|
||||||
/* Set the timer in case not all the packets were processed */
|
/* Set the timer in case not all the packets were processed */
|
||||||
if (tx_todo)
|
if (tx_todo && !port_pcpu->timer_scheduled) {
|
||||||
mvpp2_timer_set(port_pcpu);
|
port_pcpu->timer_scheduled = true;
|
||||||
}
|
hrtimer_forward_now(&port_pcpu->tx_done_timer,
|
||||||
|
MVPP2_TXDONE_HRTIMER_PERIOD_NS);
|
||||||
static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
|
|
||||||
{
|
|
||||||
struct mvpp2_port_pcpu *port_pcpu = container_of(timer,
|
|
||||||
struct mvpp2_port_pcpu,
|
|
||||||
tx_done_timer);
|
|
||||||
|
|
||||||
tasklet_schedule(&port_pcpu->tx_done_tasklet);
|
|
||||||
|
|
||||||
|
return HRTIMER_RESTART;
|
||||||
|
}
|
||||||
return HRTIMER_NORESTART;
|
return HRTIMER_NORESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3182,7 +3167,12 @@ out:
|
|||||||
txq_pcpu->count > 0) {
|
txq_pcpu->count > 0) {
|
||||||
struct mvpp2_port_pcpu *port_pcpu = per_cpu_ptr(port->pcpu, thread);
|
struct mvpp2_port_pcpu *port_pcpu = per_cpu_ptr(port->pcpu, thread);
|
||||||
|
|
||||||
mvpp2_timer_set(port_pcpu);
|
if (!port_pcpu->timer_scheduled) {
|
||||||
|
port_pcpu->timer_scheduled = true;
|
||||||
|
hrtimer_start(&port_pcpu->tx_done_timer,
|
||||||
|
MVPP2_TXDONE_HRTIMER_PERIOD_NS,
|
||||||
|
HRTIMER_MODE_REL_PINNED_SOFT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(thread, &port->priv->lock_map))
|
if (test_bit(thread, &port->priv->lock_map))
|
||||||
@@ -3619,7 +3609,6 @@ static int mvpp2_stop(struct net_device *dev)
|
|||||||
|
|
||||||
hrtimer_cancel(&port_pcpu->tx_done_timer);
|
hrtimer_cancel(&port_pcpu->tx_done_timer);
|
||||||
port_pcpu->timer_scheduled = false;
|
port_pcpu->timer_scheduled = false;
|
||||||
tasklet_kill(&port_pcpu->tx_done_tasklet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mvpp2_cleanup_rxqs(port);
|
mvpp2_cleanup_rxqs(port);
|
||||||
@@ -5183,13 +5172,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
|
|||||||
port_pcpu = per_cpu_ptr(port->pcpu, thread);
|
port_pcpu = per_cpu_ptr(port->pcpu, thread);
|
||||||
|
|
||||||
hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
|
hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
|
||||||
HRTIMER_MODE_REL_PINNED);
|
HRTIMER_MODE_REL_PINNED_SOFT);
|
||||||
port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
|
port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
|
||||||
port_pcpu->timer_scheduled = false;
|
port_pcpu->timer_scheduled = false;
|
||||||
|
port_pcpu->dev = dev;
|
||||||
tasklet_init(&port_pcpu->tx_done_tasklet,
|
|
||||||
mvpp2_tx_proc_cb,
|
|
||||||
(unsigned long)dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user