|
@@ -272,6 +272,9 @@ static int efx_poll(struct napi_struct *napi, int budget)
|
|
struct efx_nic *efx = channel->efx;
|
|
struct efx_nic *efx = channel->efx;
|
|
int spent;
|
|
int spent;
|
|
|
|
|
|
|
|
+ if (!efx_channel_lock_napi(channel))
|
|
|
|
+ return budget;
|
|
|
|
+
|
|
netif_vdbg(efx, intr, efx->net_dev,
|
|
netif_vdbg(efx, intr, efx->net_dev,
|
|
"channel %d NAPI poll executing on CPU %d\n",
|
|
"channel %d NAPI poll executing on CPU %d\n",
|
|
channel->channel, raw_smp_processor_id());
|
|
channel->channel, raw_smp_processor_id());
|
|
@@ -311,6 +314,7 @@ static int efx_poll(struct napi_struct *napi, int budget)
|
|
efx_nic_eventq_read_ack(channel);
|
|
efx_nic_eventq_read_ack(channel);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ efx_channel_unlock_napi(channel);
|
|
return spent;
|
|
return spent;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -357,7 +361,7 @@ static int efx_init_eventq(struct efx_channel *channel)
|
|
}
|
|
}
|
|
|
|
|
|
/* Enable event queue processing and NAPI */
|
|
/* Enable event queue processing and NAPI */
|
|
-static void efx_start_eventq(struct efx_channel *channel)
|
|
|
|
|
|
+void efx_start_eventq(struct efx_channel *channel)
|
|
{
|
|
{
|
|
netif_dbg(channel->efx, ifup, channel->efx->net_dev,
|
|
netif_dbg(channel->efx, ifup, channel->efx->net_dev,
|
|
"chan %d start event queue\n", channel->channel);
|
|
"chan %d start event queue\n", channel->channel);
|
|
@@ -366,17 +370,20 @@ static void efx_start_eventq(struct efx_channel *channel)
|
|
channel->enabled = true;
|
|
channel->enabled = true;
|
|
smp_wmb();
|
|
smp_wmb();
|
|
|
|
|
|
|
|
+ efx_channel_enable(channel);
|
|
napi_enable(&channel->napi_str);
|
|
napi_enable(&channel->napi_str);
|
|
efx_nic_eventq_read_ack(channel);
|
|
efx_nic_eventq_read_ack(channel);
|
|
}
|
|
}
|
|
|
|
|
|
/* Disable event queue processing and NAPI */
|
|
/* Disable event queue processing and NAPI */
|
|
-static void efx_stop_eventq(struct efx_channel *channel)
|
|
|
|
|
|
+void efx_stop_eventq(struct efx_channel *channel)
|
|
{
|
|
{
|
|
if (!channel->enabled)
|
|
if (!channel->enabled)
|
|
return;
|
|
return;
|
|
|
|
|
|
napi_disable(&channel->napi_str);
|
|
napi_disable(&channel->napi_str);
|
|
|
|
+ while (!efx_channel_disable(channel))
|
|
|
|
+ usleep_range(1000, 20000);
|
|
channel->enabled = false;
|
|
channel->enabled = false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1960,6 +1967,8 @@ static void efx_init_napi_channel(struct efx_channel *channel)
|
|
channel->napi_dev = efx->net_dev;
|
|
channel->napi_dev = efx->net_dev;
|
|
netif_napi_add(channel->napi_dev, &channel->napi_str,
|
|
netif_napi_add(channel->napi_dev, &channel->napi_str,
|
|
efx_poll, napi_weight);
|
|
efx_poll, napi_weight);
|
|
|
|
+ napi_hash_add(&channel->napi_str);
|
|
|
|
+ efx_channel_init_lock(channel);
|
|
}
|
|
}
|
|
|
|
|
|
static void efx_init_napi(struct efx_nic *efx)
|
|
static void efx_init_napi(struct efx_nic *efx)
|
|
@@ -1972,8 +1981,10 @@ static void efx_init_napi(struct efx_nic *efx)
|
|
|
|
|
|
static void efx_fini_napi_channel(struct efx_channel *channel)
|
|
static void efx_fini_napi_channel(struct efx_channel *channel)
|
|
{
|
|
{
|
|
- if (channel->napi_dev)
|
|
|
|
|
|
+ if (channel->napi_dev) {
|
|
netif_napi_del(&channel->napi_str);
|
|
netif_napi_del(&channel->napi_str);
|
|
|
|
+ napi_hash_del(&channel->napi_str);
|
|
|
|
+ }
|
|
channel->napi_dev = NULL;
|
|
channel->napi_dev = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2008,6 +2019,37 @@ static void efx_netpoll(struct net_device *net_dev)
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+#ifdef CONFIG_NET_RX_BUSY_POLL
|
|
|
|
+static int efx_busy_poll(struct napi_struct *napi)
|
|
|
|
+{
|
|
|
|
+ struct efx_channel *channel =
|
|
|
|
+ container_of(napi, struct efx_channel, napi_str);
|
|
|
|
+ struct efx_nic *efx = channel->efx;
|
|
|
|
+ int budget = 4;
|
|
|
|
+ int old_rx_packets, rx_packets;
|
|
|
|
+
|
|
|
|
+ if (!netif_running(efx->net_dev))
|
|
|
|
+ return LL_FLUSH_FAILED;
|
|
|
|
+
|
|
|
|
+ if (!efx_channel_lock_poll(channel))
|
|
|
|
+ return LL_FLUSH_BUSY;
|
|
|
|
+
|
|
|
|
+ old_rx_packets = channel->rx_queue.rx_packets;
|
|
|
|
+ efx_process_channel(channel, budget);
|
|
|
|
+
|
|
|
|
+ rx_packets = channel->rx_queue.rx_packets - old_rx_packets;
|
|
|
|
+
|
|
|
|
+ /* There is no race condition with NAPI here.
|
|
|
|
+ * NAPI will automatically be rescheduled if it yielded during busy
|
|
|
|
+ * polling, because it was not able to take the lock and thus returned
|
|
|
|
+ * the full budget.
|
|
|
|
+ */
|
|
|
|
+ efx_channel_unlock_poll(channel);
|
|
|
|
+
|
|
|
|
+ return rx_packets;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
/**************************************************************************
|
|
/**************************************************************************
|
|
*
|
|
*
|
|
* Kernel net device interface
|
|
* Kernel net device interface
|
|
@@ -2177,6 +2219,9 @@ static const struct net_device_ops efx_farch_netdev_ops = {
|
|
.ndo_poll_controller = efx_netpoll,
|
|
.ndo_poll_controller = efx_netpoll,
|
|
#endif
|
|
#endif
|
|
.ndo_setup_tc = efx_setup_tc,
|
|
.ndo_setup_tc = efx_setup_tc,
|
|
|
|
+#ifdef CONFIG_NET_RX_BUSY_POLL
|
|
|
|
+ .ndo_busy_poll = efx_busy_poll,
|
|
|
|
+#endif
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
.ndo_rx_flow_steer = efx_filter_rfs,
|
|
.ndo_rx_flow_steer = efx_filter_rfs,
|
|
#endif
|
|
#endif
|
|
@@ -2197,6 +2242,9 @@ static const struct net_device_ops efx_ef10_netdev_ops = {
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
.ndo_poll_controller = efx_netpoll,
|
|
.ndo_poll_controller = efx_netpoll,
|
|
#endif
|
|
#endif
|
|
|
|
+#ifdef CONFIG_NET_RX_BUSY_POLL
|
|
|
|
+ .ndo_busy_poll = efx_busy_poll,
|
|
|
|
+#endif
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
.ndo_rx_flow_steer = efx_filter_rfs,
|
|
.ndo_rx_flow_steer = efx_filter_rfs,
|
|
#endif
|
|
#endif
|