diff options
author | Björn Töpel <bjorn.topel@intel.com> | 2018-10-02 04:00:30 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2018-10-03 15:38:40 -0400 |
commit | 024aa5800f3246875ac824fab4bee3b4dc82f499 (patch) | |
tree | 5df69ea1228270d1937090e5eb4d660a46df6323 | |
parent | 5d826d209164b0752c883607be4cdbbcf7cab494 (diff) |
ixgbe: added Rx/Tx ring disable/enable functions
Add functions for Rx/Tx ring enable/disable. Instead of resetting the
whole device, only the affected ring is disabled or enabled.
This plumbing is used in later commits, when zero-copy AF_XDP support
is introduced.
Signed-off-by: Björn Töpel <bjorn.topel@intel.com>
Tested-by: William Tu <u9012063@gmail.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 158 |
2 files changed, 159 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 5c6fd42e90ed..265db172042a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h | |||
@@ -271,6 +271,7 @@ enum ixgbe_ring_state_t { | |||
271 | __IXGBE_TX_DETECT_HANG, | 271 | __IXGBE_TX_DETECT_HANG, |
272 | __IXGBE_HANG_CHECK_ARMED, | 272 | __IXGBE_HANG_CHECK_ARMED, |
273 | __IXGBE_TX_XDP_RING, | 273 | __IXGBE_TX_XDP_RING, |
274 | __IXGBE_TX_DISABLED, | ||
274 | }; | 275 | }; |
275 | 276 | ||
276 | #define ring_uses_build_skb(ring) \ | 277 | #define ring_uses_build_skb(ring) \ |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2928ce7653eb..47e28d9ce1e3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -8692,6 +8692,8 @@ static netdev_tx_t __ixgbe_xmit_frame(struct sk_buff *skb, | |||
8692 | return NETDEV_TX_OK; | 8692 | return NETDEV_TX_OK; |
8693 | 8693 | ||
8694 | tx_ring = ring ? ring : adapter->tx_ring[skb->queue_mapping]; | 8694 | tx_ring = ring ? ring : adapter->tx_ring[skb->queue_mapping]; |
8695 | if (unlikely(test_bit(__IXGBE_TX_DISABLED, &tx_ring->state))) | ||
8696 | return NETDEV_TX_BUSY; | ||
8695 | 8697 | ||
8696 | return ixgbe_xmit_frame_ring(skb, adapter, tx_ring); | 8698 | return ixgbe_xmit_frame_ring(skb, adapter, tx_ring); |
8697 | } | 8699 | } |
@@ -10238,6 +10240,9 @@ static int ixgbe_xdp_xmit(struct net_device *dev, int n, | |||
10238 | if (unlikely(!ring)) | 10240 | if (unlikely(!ring)) |
10239 | return -ENXIO; | 10241 | return -ENXIO; |
10240 | 10242 | ||
10243 | if (unlikely(test_bit(__IXGBE_TX_DISABLED, &ring->state))) | ||
10244 | return -ENXIO; | ||
10245 | |||
10241 | for (i = 0; i < n; i++) { | 10246 | for (i = 0; i < n; i++) { |
10242 | struct xdp_frame *xdpf = frames[i]; | 10247 | struct xdp_frame *xdpf = frames[i]; |
10243 | int err; | 10248 | int err; |
@@ -10301,6 +10306,159 @@ static const struct net_device_ops ixgbe_netdev_ops = { | |||
10301 | .ndo_xdp_xmit = ixgbe_xdp_xmit, | 10306 | .ndo_xdp_xmit = ixgbe_xdp_xmit, |
10302 | }; | 10307 | }; |
10303 | 10308 | ||
10309 | static void ixgbe_disable_txr_hw(struct ixgbe_adapter *adapter, | ||
10310 | struct ixgbe_ring *tx_ring) | ||
10311 | { | ||
10312 | unsigned long wait_delay, delay_interval; | ||
10313 | struct ixgbe_hw *hw = &adapter->hw; | ||
10314 | u8 reg_idx = tx_ring->reg_idx; | ||
10315 | int wait_loop; | ||
10316 | u32 txdctl; | ||
10317 | |||
10318 | IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH); | ||
10319 | |||
10320 | /* delay mechanism from ixgbe_disable_tx */ | ||
10321 | delay_interval = ixgbe_get_completion_timeout(adapter) / 100; | ||
10322 | |||
10323 | wait_loop = IXGBE_MAX_RX_DESC_POLL; | ||
10324 | wait_delay = delay_interval; | ||
10325 | |||
10326 | while (wait_loop--) { | ||
10327 | usleep_range(wait_delay, wait_delay + 10); | ||
10328 | wait_delay += delay_interval * 2; | ||
10329 | txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); | ||
10330 | |||
10331 | if (!(txdctl & IXGBE_TXDCTL_ENABLE)) | ||
10332 | return; | ||
10333 | } | ||
10334 | |||
10335 | e_err(drv, "TXDCTL.ENABLE not cleared within the polling period\n"); | ||
10336 | } | ||
10337 | |||
10338 | static void ixgbe_disable_txr(struct ixgbe_adapter *adapter, | ||
10339 | struct ixgbe_ring *tx_ring) | ||
10340 | { | ||
10341 | set_bit(__IXGBE_TX_DISABLED, &tx_ring->state); | ||
10342 | ixgbe_disable_txr_hw(adapter, tx_ring); | ||
10343 | } | ||
10344 | |||
10345 | static void ixgbe_disable_rxr_hw(struct ixgbe_adapter *adapter, | ||
10346 | struct ixgbe_ring *rx_ring) | ||
10347 | { | ||
10348 | unsigned long wait_delay, delay_interval; | ||
10349 | struct ixgbe_hw *hw = &adapter->hw; | ||
10350 | u8 reg_idx = rx_ring->reg_idx; | ||
10351 | int wait_loop; | ||
10352 | u32 rxdctl; | ||
10353 | |||
10354 | rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); | ||
10355 | rxdctl &= ~IXGBE_RXDCTL_ENABLE; | ||
10356 | rxdctl |= IXGBE_RXDCTL_SWFLSH; | ||
10357 | |||
10358 | /* write value back with RXDCTL.ENABLE bit cleared */ | ||
10359 | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); | ||
10360 | |||
10361 | /* RXDCTL.EN may not change on 82598 if link is down, so skip it */ | ||
10362 | if (hw->mac.type == ixgbe_mac_82598EB && | ||
10363 | !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) | ||
10364 | return; | ||
10365 | |||
10366 | /* delay mechanism from ixgbe_disable_rx */ | ||
10367 | delay_interval = ixgbe_get_completion_timeout(adapter) / 100; | ||
10368 | |||
10369 | wait_loop = IXGBE_MAX_RX_DESC_POLL; | ||
10370 | wait_delay = delay_interval; | ||
10371 | |||
10372 | while (wait_loop--) { | ||
10373 | usleep_range(wait_delay, wait_delay + 10); | ||
10374 | wait_delay += delay_interval * 2; | ||
10375 | rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); | ||
10376 | |||
10377 | if (!(rxdctl & IXGBE_RXDCTL_ENABLE)) | ||
10378 | return; | ||
10379 | } | ||
10380 | |||
10381 | e_err(drv, "RXDCTL.ENABLE not cleared within the polling period\n"); | ||
10382 | } | ||
10383 | |||
10384 | static void ixgbe_reset_txr_stats(struct ixgbe_ring *tx_ring) | ||
10385 | { | ||
10386 | memset(&tx_ring->stats, 0, sizeof(tx_ring->stats)); | ||
10387 | memset(&tx_ring->tx_stats, 0, sizeof(tx_ring->tx_stats)); | ||
10388 | } | ||
10389 | |||
10390 | static void ixgbe_reset_rxr_stats(struct ixgbe_ring *rx_ring) | ||
10391 | { | ||
10392 | memset(&rx_ring->stats, 0, sizeof(rx_ring->stats)); | ||
10393 | memset(&rx_ring->rx_stats, 0, sizeof(rx_ring->rx_stats)); | ||
10394 | } | ||
10395 | |||
10396 | /** | ||
10397 | * ixgbe_txrx_ring_disable - Disable Rx/Tx/XDP Tx rings | ||
10398 | * @adapter: adapter structure | ||
10399 | * @ring: ring index | ||
10400 | * | ||
10401 | * This function disables a certain Rx/Tx/XDP Tx ring. The function | ||
10402 | * assumes that the netdev is running. | ||
10403 | **/ | ||
10404 | void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring) | ||
10405 | { | ||
10406 | struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring; | ||
10407 | |||
10408 | rx_ring = adapter->rx_ring[ring]; | ||
10409 | tx_ring = adapter->tx_ring[ring]; | ||
10410 | xdp_ring = adapter->xdp_ring[ring]; | ||
10411 | |||
10412 | ixgbe_disable_txr(adapter, tx_ring); | ||
10413 | if (xdp_ring) | ||
10414 | ixgbe_disable_txr(adapter, xdp_ring); | ||
10415 | ixgbe_disable_rxr_hw(adapter, rx_ring); | ||
10416 | |||
10417 | if (xdp_ring) | ||
10418 | synchronize_sched(); | ||
10419 | |||
10420 | /* Rx/Tx/XDP Tx share the same napi context. */ | ||
10421 | napi_disable(&rx_ring->q_vector->napi); | ||
10422 | |||
10423 | ixgbe_clean_tx_ring(tx_ring); | ||
10424 | if (xdp_ring) | ||
10425 | ixgbe_clean_tx_ring(xdp_ring); | ||
10426 | ixgbe_clean_rx_ring(rx_ring); | ||
10427 | |||
10428 | ixgbe_reset_txr_stats(tx_ring); | ||
10429 | if (xdp_ring) | ||
10430 | ixgbe_reset_txr_stats(xdp_ring); | ||
10431 | ixgbe_reset_rxr_stats(rx_ring); | ||
10432 | } | ||
10433 | |||
10434 | /** | ||
10435 | * ixgbe_txrx_ring_enable - Enable Rx/Tx/XDP Tx rings | ||
10436 | * @adapter: adapter structure | ||
10437 | * @ring: ring index | ||
10438 | * | ||
10439 | * This function enables a certain Rx/Tx/XDP Tx ring. The function | ||
10440 | * assumes that the netdev is running. | ||
10441 | **/ | ||
10442 | void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring) | ||
10443 | { | ||
10444 | struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring; | ||
10445 | |||
10446 | rx_ring = adapter->rx_ring[ring]; | ||
10447 | tx_ring = adapter->tx_ring[ring]; | ||
10448 | xdp_ring = adapter->xdp_ring[ring]; | ||
10449 | |||
10450 | /* Rx/Tx/XDP Tx share the same napi context. */ | ||
10451 | napi_enable(&rx_ring->q_vector->napi); | ||
10452 | |||
10453 | ixgbe_configure_tx_ring(adapter, tx_ring); | ||
10454 | if (xdp_ring) | ||
10455 | ixgbe_configure_tx_ring(adapter, xdp_ring); | ||
10456 | ixgbe_configure_rx_ring(adapter, rx_ring); | ||
10457 | |||
10458 | clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state); | ||
10459 | clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state); | ||
10460 | } | ||
10461 | |||
10304 | /** | 10462 | /** |
10305 | * ixgbe_enumerate_functions - Get the number of ports this device has | 10463 | * ixgbe_enumerate_functions - Get the number of ports this device has |
10306 | * @adapter: adapter structure | 10464 | * @adapter: adapter structure |