|
24 | 24 | #define GVE_VERSION "1.0.0" |
25 | 25 | #define GVE_VERSION_PREFIX "GVE-" |
26 | 26 |
|
| 27 | +// Minimum amount of time between queue kicks in msec (10 seconds) |
| 28 | +#define MIN_TX_TIMEOUT_GAP (1000 * 10) |
| 29 | + |
27 | 30 | const char gve_version_str[] = GVE_VERSION; |
28 | 31 | static const char gve_version_prefix[] = GVE_VERSION_PREFIX; |
29 | 32 |
|
@@ -1121,9 +1124,47 @@ static void gve_turnup(struct gve_priv *priv) |
1121 | 1124 |
|
1122 | 1125 | static void gve_tx_timeout(struct net_device *dev, unsigned int txqueue) |
1123 | 1126 | { |
1124 | | - struct gve_priv *priv = netdev_priv(dev); |
| 1127 | + struct gve_notify_block *block; |
| 1128 | + struct gve_tx_ring *tx = NULL; |
| 1129 | + struct gve_priv *priv; |
| 1130 | + u32 last_nic_done; |
| 1131 | + u32 current_time; |
| 1132 | + u32 ntfy_idx; |
| 1133 | + |
| 1134 | + netdev_info(dev, "Timeout on tx queue, %d", txqueue); |
| 1135 | + priv = netdev_priv(dev); |
| 1136 | + if (txqueue > priv->tx_cfg.num_queues) |
| 1137 | + goto reset; |
| 1138 | + |
| 1139 | + ntfy_idx = gve_tx_idx_to_ntfy(priv, txqueue); |
| 1140 | + if (ntfy_idx > priv->num_ntfy_blks) |
| 1141 | + goto reset; |
| 1142 | + |
| 1143 | + block = &priv->ntfy_blocks[ntfy_idx]; |
| 1144 | + tx = block->tx; |
1125 | 1145 |
|
| 1146 | + current_time = jiffies_to_msecs(jiffies); |
| 1147 | + if (tx->last_kick_msec + MIN_TX_TIMEOUT_GAP > current_time) |
| 1148 | + goto reset; |
| 1149 | + |
| 1150 | + /* Check to see if there are missed completions, which will allow us to |
| 1151 | + * kick the queue. |
| 1152 | + */ |
| 1153 | + last_nic_done = gve_tx_load_event_counter(priv, tx); |
| 1154 | + if (last_nic_done - tx->done) { |
| 1155 | + netdev_info(dev, "Kicking queue %d", txqueue); |
| 1156 | + iowrite32be(GVE_IRQ_MASK, gve_irq_doorbell(priv, block)); |
| 1157 | + napi_schedule(&block->napi); |
| 1158 | + tx->last_kick_msec = current_time; |
| 1159 | + goto out; |
| 1160 | + } // Else reset. |
| 1161 | + |
| 1162 | +reset: |
1126 | 1163 | gve_schedule_reset(priv); |
| 1164 | + |
| 1165 | +out: |
| 1166 | + if (tx) |
| 1167 | + tx->queue_timeout++; |
1127 | 1168 | priv->tx_timeo_cnt++; |
1128 | 1169 | } |
1129 | 1170 |
|
@@ -1252,6 +1293,11 @@ void gve_handle_report_stats(struct gve_priv *priv) |
1252 | 1293 | .value = cpu_to_be64(last_completion), |
1253 | 1294 | .queue_id = cpu_to_be32(idx), |
1254 | 1295 | }; |
| 1296 | + stats[stats_idx++] = (struct stats) { |
| 1297 | + .stat_name = cpu_to_be32(TX_TIMEOUT_CNT), |
| 1298 | + .value = cpu_to_be64(priv->tx[idx].queue_timeout), |
| 1299 | + .queue_id = cpu_to_be32(idx), |
| 1300 | + }; |
1255 | 1301 | } |
1256 | 1302 | } |
1257 | 1303 | /* rx stats */ |
|
0 commit comments