|
@@ -2411,9 +2411,11 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
|
|
|
/* TSOv2 is a limited resource that can only be configured on a limited
|
|
|
* number of queues. TSO without checksum offload is not really a thing,
|
|
|
* so we only enable it for those queues.
|
|
|
+ * TSOv2 cannot be used with Hardware timestamping.
|
|
|
*/
|
|
|
if (csum_offload && (nic_data->datapath_caps2 &
|
|
|
- (1 << MC_CMD_GET_CAPABILITIES_V2_OUT_TX_TSO_V2_LBN))) {
|
|
|
+ (1 << MC_CMD_GET_CAPABILITIES_V2_OUT_TX_TSO_V2_LBN)) &&
|
|
|
+ !tx_queue->timestamping) {
|
|
|
tso_v2 = true;
|
|
|
netif_dbg(efx, hw, efx->net_dev, "Using TSOv2 for channel %u\n",
|
|
|
channel->channel);
|
|
@@ -2439,14 +2441,16 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
|
|
|
inlen = MC_CMD_INIT_TXQ_IN_LEN(entries);
|
|
|
|
|
|
do {
|
|
|
- MCDI_POPULATE_DWORD_3(inbuf, INIT_TXQ_IN_FLAGS,
|
|
|
+ MCDI_POPULATE_DWORD_4(inbuf, INIT_TXQ_IN_FLAGS,
|
|
|
/* This flag was removed from mcdi_pcol.h for
|
|
|
* the non-_EXT version of INIT_TXQ. However,
|
|
|
* firmware still honours it.
|
|
|
*/
|
|
|
INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, tso_v2,
|
|
|
INIT_TXQ_IN_FLAG_IP_CSUM_DIS, !csum_offload,
|
|
|
- INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, !csum_offload);
|
|
|
+ INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, !csum_offload,
|
|
|
+ INIT_TXQ_EXT_IN_FLAG_TIMESTAMP,
|
|
|
+ tx_queue->timestamping);
|
|
|
|
|
|
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_INIT_TXQ, inbuf, inlen,
|
|
|
NULL, 0, NULL);
|
|
@@ -2472,12 +2476,13 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
|
|
|
tx_queue->buffer[0].flags = EFX_TX_BUF_OPTION;
|
|
|
tx_queue->insert_count = 1;
|
|
|
txd = efx_tx_desc(tx_queue, 0);
|
|
|
- EFX_POPULATE_QWORD_4(*txd,
|
|
|
+ EFX_POPULATE_QWORD_5(*txd,
|
|
|
ESF_DZ_TX_DESC_IS_OPT, true,
|
|
|
ESF_DZ_TX_OPTION_TYPE,
|
|
|
ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
|
|
|
ESF_DZ_TX_OPTION_UDP_TCP_CSUM, csum_offload,
|
|
|
- ESF_DZ_TX_OPTION_IP_CSUM, csum_offload);
|
|
|
+ ESF_DZ_TX_OPTION_IP_CSUM, csum_offload,
|
|
|
+ ESF_DZ_TX_TIMESTAMP, tx_queue->timestamping);
|
|
|
tx_queue->write_count = 1;
|
|
|
|
|
|
if (tso_v2) {
|
|
@@ -3572,6 +3577,17 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel,
|
|
|
return n_packets;
|
|
|
}
|
|
|
|
|
|
+static u32 efx_ef10_extract_event_ts(efx_qword_t *event)
|
|
|
+{
|
|
|
+ u32 tstamp;
|
|
|
+
|
|
|
+ tstamp = EFX_QWORD_FIELD(*event, TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI);
|
|
|
+ tstamp <<= 16;
|
|
|
+ tstamp |= EFX_QWORD_FIELD(*event, TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO);
|
|
|
+
|
|
|
+ return tstamp;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
|
|
|
{
|
|
@@ -3579,6 +3595,8 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
|
|
|
struct efx_tx_queue *tx_queue;
|
|
|
unsigned int tx_ev_desc_ptr;
|
|
|
unsigned int tx_ev_q_label;
|
|
|
+ unsigned int tx_ev_type;
|
|
|
+ u64 ts_part;
|
|
|
|
|
|
if (unlikely(READ_ONCE(efx->reset_pending)))
|
|
|
return;
|
|
@@ -3586,12 +3604,65 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
|
|
|
if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT)))
|
|
|
return;
|
|
|
|
|
|
- /* Transmit completion */
|
|
|
- tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX);
|
|
|
+ /* Get the transmit queue */
|
|
|
tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL);
|
|
|
tx_queue = efx_channel_get_tx_queue(channel,
|
|
|
tx_ev_q_label % EFX_TXQ_TYPES);
|
|
|
- efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
|
|
|
+
|
|
|
+ if (!tx_queue->timestamping) {
|
|
|
+ /* Transmit completion */
|
|
|
+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX);
|
|
|
+ efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Transmit timestamps are only available for 8XXX series. They result
|
|
|
+ * in three events per packet. These occur in order, and are:
|
|
|
+ * - the normal completion event
|
|
|
+ * - the low part of the timestamp
|
|
|
+ * - the high part of the timestamp
|
|
|
+ *
|
|
|
+ * Each part of the timestamp is itself split across two 16 bit
|
|
|
+ * fields in the event.
|
|
|
+ */
|
|
|
+ tx_ev_type = EFX_QWORD_FIELD(*event, ESF_EZ_TX_SOFT1);
|
|
|
+
|
|
|
+ switch (tx_ev_type) {
|
|
|
+ case TX_TIMESTAMP_EVENT_TX_EV_COMPLETION:
|
|
|
+ /* In case of Queue flush or FLR, we might have received
|
|
|
+ * the previous TX completion event but not the Timestamp
|
|
|
+ * events.
|
|
|
+ */
|
|
|
+ if (tx_queue->completed_desc_ptr != tx_queue->ptr_mask)
|
|
|
+ efx_xmit_done(tx_queue, tx_queue->completed_desc_ptr);
|
|
|
+
|
|
|
+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event,
|
|
|
+ ESF_DZ_TX_DESCR_INDX);
|
|
|
+ tx_queue->completed_desc_ptr =
|
|
|
+ tx_ev_desc_ptr & tx_queue->ptr_mask;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_LO:
|
|
|
+ ts_part = efx_ef10_extract_event_ts(event);
|
|
|
+ tx_queue->completed_timestamp_minor = ts_part;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_HI:
|
|
|
+ ts_part = efx_ef10_extract_event_ts(event);
|
|
|
+ tx_queue->completed_timestamp_major = ts_part;
|
|
|
+
|
|
|
+ efx_xmit_done(tx_queue, tx_queue->completed_desc_ptr);
|
|
|
+ tx_queue->completed_desc_ptr = tx_queue->ptr_mask;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ netif_err(efx, hw, efx->net_dev,
|
|
|
+ "channel %d unknown tx event type %d (data "
|
|
|
+ EFX_QWORD_FMT ")\n",
|
|
|
+ channel->channel, tx_ev_type,
|
|
|
+ EFX_QWORD_VAL(*event));
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void
|