aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaghu Vatsavayi <raghu.vatsavayi@cavium.com>2018-03-29 14:13:22 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-30 14:16:19 -0400
commitccdd0b4c35f2adb7434ed69a89bc68bb6e9089ea (patch)
treedc0a8e01b3a7cedf17724aff50ad049a220ee3af
parent6f14f49ce5eb00f533133df06c663fbaea13cd50 (diff)
liquidio: prevent rx queues from getting stalled
This commit has fix for RX traffic issues when we stress test the driver with continuous ifconfig up/down under very high traffic conditions. Reason for the issue is that, in existing liquidio_stop function NAPI is disabled even before actual FW/HW interface is brought down via send_rx_ctrl_cmd(lio, 0). Between time frame of NAPI disable and actual interface down in firmware, firmware continuously enqueues rx traffic to host. When interrupt happens for new packets, host irq handler fails in scheduling NAPI as the NAPI is already disabled. After "ifconfig <iface> up", Host re-enables NAPI but cannot schedule it until it receives another Rx interrupt. Host never receives Rx interrupt as it never cleared the Rx interrupt it received during interface down operation. NIC Rx interrupt gets cleared only when Host processes queue and clears the queue counts. Above anomaly leads to other issues like packet overflow in FW/HW queues, backpressure. Fix: This commit fixes this issue by disabling NAPI only after informing firmware to stop queueing packets to host via send_rx_ctrl_cmd(lio, 0). send_rx_ctrl_cmd is not visible in the patch as it is already there in the code. The DOWN command also waits for any pending packets to be processed by NAPI so that the deadlock will not occur. Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@cavium.com> Acked-by: Derek Chickles <derek.chickles@cavium.com> Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_core.c23
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c25
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_vf_main.c23
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_network.h1
4 files changed, 53 insertions, 19 deletions
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c
index 73e70e076e61..2a94eee943b2 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_core.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c
@@ -1146,3 +1146,26 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
1146 octeon_free_soft_command(oct, sc); 1146 octeon_free_soft_command(oct, sc);
1147 return 0; 1147 return 0;
1148} 1148}
1149
1150int lio_wait_for_clean_oq(struct octeon_device *oct)
1151{
1152 int retry = 100, pending_pkts = 0;
1153 int idx;
1154
1155 do {
1156 pending_pkts = 0;
1157
1158 for (idx = 0; idx < MAX_OCTEON_OUTPUT_QUEUES(oct); idx++) {
1159 if (!(oct->io_qmask.oq & BIT_ULL(idx)))
1160 continue;
1161 pending_pkts +=
1162 atomic_read(&oct->droq[idx]->pkts_pending);
1163 }
1164
1165 if (pending_pkts > 0)
1166 schedule_timeout_uninterruptible(1);
1167
1168 } while (retry-- && pending_pkts);
1169
1170 return pending_pkts;
1171}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index 43c5ba0af12b..603a144d3d9c 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -2084,16 +2084,6 @@ static int liquidio_stop(struct net_device *netdev)
2084 struct octeon_device *oct = lio->oct_dev; 2084 struct octeon_device *oct = lio->oct_dev;
2085 struct napi_struct *napi, *n; 2085 struct napi_struct *napi, *n;
2086 2086
2087 if (oct->props[lio->ifidx].napi_enabled) {
2088 list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
2089 napi_disable(napi);
2090
2091 oct->props[lio->ifidx].napi_enabled = 0;
2092
2093 if (OCTEON_CN23XX_PF(oct))
2094 oct->droq[0]->ops.poll_mode = 0;
2095 }
2096
2097 ifstate_reset(lio, LIO_IFSTATE_RUNNING); 2087 ifstate_reset(lio, LIO_IFSTATE_RUNNING);
2098 2088
2099 netif_tx_disable(netdev); 2089 netif_tx_disable(netdev);
@@ -2119,6 +2109,21 @@ static int liquidio_stop(struct net_device *netdev)
2119 lio->ptp_clock = NULL; 2109 lio->ptp_clock = NULL;
2120 } 2110 }
2121 2111
2112 /* Wait for any pending Rx descriptors */
2113 if (lio_wait_for_clean_oq(oct))
2114 netif_info(lio, rx_err, lio->netdev,
2115 "Proceeding with stop interface after partial RX desc processing\n");
2116
2117 if (oct->props[lio->ifidx].napi_enabled == 1) {
2118 list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
2119 napi_disable(napi);
2120
2121 oct->props[lio->ifidx].napi_enabled = 0;
2122
2123 if (OCTEON_CN23XX_PF(oct))
2124 oct->droq[0]->ops.poll_mode = 0;
2125 }
2126
2122 dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); 2127 dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
2123 2128
2124 return 0; 2129 return 0;
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
index dc62698bdaf7..f92dfa411de6 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
@@ -1138,15 +1138,6 @@ static int liquidio_stop(struct net_device *netdev)
1138 /* tell Octeon to stop forwarding packets to host */ 1138 /* tell Octeon to stop forwarding packets to host */
1139 send_rx_ctrl_cmd(lio, 0); 1139 send_rx_ctrl_cmd(lio, 0);
1140 1140
1141 if (oct->props[lio->ifidx].napi_enabled) {
1142 list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
1143 napi_disable(napi);
1144
1145 oct->props[lio->ifidx].napi_enabled = 0;
1146
1147 oct->droq[0]->ops.poll_mode = 0;
1148 }
1149
1150 netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n"); 1141 netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n");
1151 /* Inform that netif carrier is down */ 1142 /* Inform that netif carrier is down */
1152 lio->intf_open = 0; 1143 lio->intf_open = 0;
@@ -1159,6 +1150,20 @@ static int liquidio_stop(struct net_device *netdev)
1159 1150
1160 stop_txqs(netdev); 1151 stop_txqs(netdev);
1161 1152
1153 /* Wait for any pending Rx descriptors */
1154 if (lio_wait_for_clean_oq(oct))
1155 netif_info(lio, rx_err, lio->netdev,
1156 "Proceeding with stop interface after partial RX desc processing\n");
1157
1158 if (oct->props[lio->ifidx].napi_enabled == 1) {
1159 list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
1160 napi_disable(napi);
1161
1162 oct->props[lio->ifidx].napi_enabled = 0;
1163
1164 oct->droq[0]->ops.poll_mode = 0;
1165 }
1166
1162 dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); 1167 dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
1163 1168
1164 return 0; 1169 return 0;
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
index 8782206271b6..4069710796a8 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
@@ -190,6 +190,7 @@ irqreturn_t liquidio_msix_intr_handler(int irq __attribute__((unused)),
190 190
191int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs); 191int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs);
192 192
193int lio_wait_for_clean_oq(struct octeon_device *oct);
193/** 194/**
194 * \brief Register ethtool operations 195 * \brief Register ethtool operations
195 * @param netdev pointer to network device 196 * @param netdev pointer to network device