Commit 2611df7a authored by David S. Miller's avatar David S. Miller

Merge branch 'sfc-support-PTP-on-8000-and-X2000-series-NICs'

Edward Cree says:

====================
sfc: support PTP on 8000 and X2000 series NICs

Starting from the 8000-series (Medford 1), SFC NICs can timestamp TX packets
 sent through an ordinary DMA queue, rather than a special control-plane
 operation as in the 7000-series.  Patches 2-8 implement support for this.
The X2000-series (Medford 2) changes the format of timestamps, from seconds+
 (2^27)ths to seconds + quarter nanoseconds, as well as changing the shift
 of the frequency adjustment for increased precision.  Patches 9-12
 implement support for these changes.
Patch #1 is an unrelated fix for NAPI budget handling, needed in order for
 TX completion changes in the later patches to apply cleanly.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fb07a820 88a4fb5f
...@@ -322,6 +322,25 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx) ...@@ -322,6 +322,25 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
return 0; return 0;
} }
static void efx_ef10_read_licensed_features(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_LICENSING_V3_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_LICENSING_V3_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, LICENSING_V3_IN_OP,
MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE);
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_LICENSING_V3, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc || (outlen < MC_CMD_LICENSING_V3_OUT_LEN))
return;
nic_data->licensed_features = MCDI_QWORD(outbuf,
LICENSING_V3_OUT_LICENSED_FEATURES);
}
static int efx_ef10_get_sysclk_freq(struct efx_nic *efx) static int efx_ef10_get_sysclk_freq(struct efx_nic *efx)
{ {
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLOCK_OUT_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLOCK_OUT_LEN);
...@@ -722,6 +741,8 @@ static int efx_ef10_probe(struct efx_nic *efx) ...@@ -722,6 +741,8 @@ static int efx_ef10_probe(struct efx_nic *efx)
if (rc < 0) if (rc < 0)
goto fail5; goto fail5;
efx_ef10_read_licensed_features(efx);
/* We can have one VI for each vi_stride-byte region. /* We can have one VI for each vi_stride-byte region.
* However, until we use TX option descriptors we need two TX queues * However, until we use TX option descriptors we need two TX queues
* per channel. * per channel.
...@@ -760,14 +781,7 @@ static int efx_ef10_probe(struct efx_nic *efx) ...@@ -760,14 +781,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
if (rc && rc != -EPERM) if (rc && rc != -EPERM)
goto fail5; goto fail5;
rc = efx_ptp_probe(efx, NULL); efx_ptp_defer_probe_with_channel(efx);
/* Failure to probe PTP is not fatal.
* In the case of EPERM, efx_ptp_probe will print its own message (in
* efx_ptp_get_attributes()), so we don't need to.
*/
if (rc && rc != -EPERM)
netif_warn(efx, drv, efx->net_dev,
"Failed to probe PTP, rc=%d\n", rc);
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
if ((efx->pci_dev->physfn) && (!efx->pci_dev->is_physfn)) { if ((efx->pci_dev->physfn) && (!efx->pci_dev->is_physfn)) {
...@@ -937,6 +951,11 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx) ...@@ -937,6 +951,11 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx)
/* Link a buffer to each TX queue */ /* Link a buffer to each TX queue */
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx) {
/* Extra channels, even those with TXQs (PTP), do not require
* PIO resources.
*/
if (!channel->type->want_pio)
continue;
efx_for_each_channel_tx_queue(tx_queue, channel) { efx_for_each_channel_tx_queue(tx_queue, channel) {
/* We assign the PIO buffers to queues in /* We assign the PIO buffers to queues in
* reverse order to allow for the following * reverse order to allow for the following
...@@ -1284,7 +1303,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) ...@@ -1284,7 +1303,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
void __iomem *membase; void __iomem *membase;
int rc; int rc;
channel_vis = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); channel_vis = max(efx->n_channels,
(efx->n_tx_channels + efx->n_extra_tx_channels) *
EFX_TXQ_TYPES);
#ifdef EFX_USE_PIO #ifdef EFX_USE_PIO
/* Try to allocate PIO buffers if wanted and if the full /* Try to allocate PIO buffers if wanted and if the full
...@@ -2408,12 +2429,25 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) ...@@ -2408,12 +2429,25 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
int i; int i;
BUILD_BUG_ON(MC_CMD_INIT_TXQ_OUT_LEN != 0); BUILD_BUG_ON(MC_CMD_INIT_TXQ_OUT_LEN != 0);
/* Only attempt to enable TX timestamping if we have the license for it,
* otherwise TXQ init will fail
*/
if (!(nic_data->licensed_features &
(1 << LICENSED_V3_FEATURES_TX_TIMESTAMPS_LBN))) {
tx_queue->timestamping = false;
/* Disable sync events on this channel. */
if (efx->type->ptp_set_ts_sync_events)
efx->type->ptp_set_ts_sync_events(efx, false, false);
}
/* TSOv2 is a limited resource that can only be configured on a limited /* 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, * number of queues. TSO without checksum offload is not really a thing,
* so we only enable it for those queues. * so we only enable it for those queues.
* TSOv2 cannot be used with Hardware timestamping.
*/ */
if (csum_offload && (nic_data->datapath_caps2 & 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; tso_v2 = true;
netif_dbg(efx, hw, efx->net_dev, "Using TSOv2 for channel %u\n", netif_dbg(efx, hw, efx->net_dev, "Using TSOv2 for channel %u\n",
channel->channel); channel->channel);
...@@ -2439,14 +2473,16 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) ...@@ -2439,14 +2473,16 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
inlen = MC_CMD_INIT_TXQ_IN_LEN(entries); inlen = MC_CMD_INIT_TXQ_IN_LEN(entries);
do { 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 /* This flag was removed from mcdi_pcol.h for
* the non-_EXT version of INIT_TXQ. However, * the non-_EXT version of INIT_TXQ. However,
* firmware still honours it. * firmware still honours it.
*/ */
INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, tso_v2, INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, tso_v2,
INIT_TXQ_IN_FLAG_IP_CSUM_DIS, !csum_offload, 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, rc = efx_mcdi_rpc_quiet(efx, MC_CMD_INIT_TXQ, inbuf, inlen,
NULL, 0, NULL); NULL, 0, NULL);
...@@ -2472,12 +2508,13 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) ...@@ -2472,12 +2508,13 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
tx_queue->buffer[0].flags = EFX_TX_BUF_OPTION; tx_queue->buffer[0].flags = EFX_TX_BUF_OPTION;
tx_queue->insert_count = 1; tx_queue->insert_count = 1;
txd = efx_tx_desc(tx_queue, 0); 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_DESC_IS_OPT, true,
ESF_DZ_TX_OPTION_TYPE, ESF_DZ_TX_OPTION_TYPE,
ESE_DZ_TX_OPTION_DESC_CRC_CSUM, ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
ESF_DZ_TX_OPTION_UDP_TCP_CSUM, csum_offload, 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; tx_queue->write_count = 1;
if (tso_v2) { if (tso_v2) {
...@@ -3572,31 +3609,92 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel, ...@@ -3572,31 +3609,92 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel,
return n_packets; return n_packets;
} }
static int 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) efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
struct efx_tx_queue *tx_queue; struct efx_tx_queue *tx_queue;
unsigned int tx_ev_desc_ptr; unsigned int tx_ev_desc_ptr;
unsigned int tx_ev_q_label; unsigned int tx_ev_q_label;
int tx_descs = 0; unsigned int tx_ev_type;
u64 ts_part;
if (unlikely(READ_ONCE(efx->reset_pending))) if (unlikely(READ_ONCE(efx->reset_pending)))
return 0; return;
if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT))) if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT)))
return 0; return;
/* Transmit completion */ /* Get the transmit queue */
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX);
tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL); tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL);
tx_queue = efx_channel_get_tx_queue(channel, tx_queue = efx_channel_get_tx_queue(channel,
tx_ev_q_label % EFX_TXQ_TYPES); tx_ev_q_label % EFX_TXQ_TYPES);
tx_descs = ((tx_ev_desc_ptr + 1 - tx_queue->read_count) &
tx_queue->ptr_mask);
efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
return tx_descs; 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 static void
...@@ -3658,7 +3756,6 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota) ...@@ -3658,7 +3756,6 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
efx_qword_t event, *p_event; efx_qword_t event, *p_event;
unsigned int read_ptr; unsigned int read_ptr;
int ev_code; int ev_code;
int tx_descs = 0;
int spent = 0; int spent = 0;
if (quota <= 0) if (quota <= 0)
...@@ -3698,13 +3795,7 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota) ...@@ -3698,13 +3795,7 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
} }
break; break;
case ESE_DZ_EV_CODE_TX_EV: case ESE_DZ_EV_CODE_TX_EV:
tx_descs += efx_ef10_handle_tx_event(channel, &event); efx_ef10_handle_tx_event(channel, &event);
if (tx_descs > efx->txq_entries) {
spent = quota;
goto out;
} else if (++spent == quota) {
goto out;
}
break; break;
case ESE_DZ_EV_CODE_DRIVER_EV: case ESE_DZ_EV_CODE_DRIVER_EV:
efx_ef10_handle_driver_event(channel, &event); efx_ef10_handle_driver_event(channel, &event);
...@@ -6179,7 +6270,8 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en, ...@@ -6179,7 +6270,8 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en,
efx_ef10_rx_enable_timestamping : efx_ef10_rx_enable_timestamping :
efx_ef10_rx_disable_timestamping; efx_ef10_rx_disable_timestamping;
efx_for_each_channel(channel, efx) { channel = efx_ptp_channel(efx);
if (channel) {
int rc = set(channel, temp); int rc = set(channel, temp);
if (en && rc != 0) { if (en && rc != 0) {
efx_ef10_ptp_set_ts_sync_events(efx, false, temp); efx_ef10_ptp_set_ts_sync_events(efx, false, temp);
......
...@@ -896,12 +896,20 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) ...@@ -896,12 +896,20 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
} }
bool efx_default_channel_want_txqs(struct efx_channel *channel)
{
return channel->channel - channel->efx->tx_channel_offset <
channel->efx->n_tx_channels;
}
static const struct efx_channel_type efx_default_channel_type = { static const struct efx_channel_type efx_default_channel_type = {
.pre_probe = efx_channel_dummy_op_int, .pre_probe = efx_channel_dummy_op_int,
.post_remove = efx_channel_dummy_op_void, .post_remove = efx_channel_dummy_op_void,
.get_name = efx_get_channel_name, .get_name = efx_get_channel_name,
.copy = efx_copy_channel, .copy = efx_copy_channel,
.want_txqs = efx_default_channel_want_txqs,
.keep_eventq = false, .keep_eventq = false,
.want_pio = true,
}; };
int efx_channel_dummy_op_int(struct efx_channel *channel) int efx_channel_dummy_op_int(struct efx_channel *channel)
...@@ -1501,6 +1509,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1501,6 +1509,7 @@ static int efx_probe_interrupts(struct efx_nic *efx)
} }
/* Assign extra channels if possible */ /* Assign extra channels if possible */
efx->n_extra_tx_channels = 0;
j = efx->n_channels; j = efx->n_channels;
for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) { for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
if (!efx->extra_channel_type[i]) if (!efx->extra_channel_type[i])
...@@ -1512,6 +1521,8 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1512,6 +1521,8 @@ static int efx_probe_interrupts(struct efx_nic *efx)
--j; --j;
efx_get_channel(efx, j)->type = efx_get_channel(efx, j)->type =
efx->extra_channel_type[i]; efx->extra_channel_type[i];
if (efx_channel_has_tx_queues(efx_get_channel(efx, j)))
efx->n_extra_tx_channels++;
} }
} }
......
...@@ -818,17 +818,16 @@ static void efx_farch_magic_event(struct efx_channel *channel, u32 magic) ...@@ -818,17 +818,16 @@ static void efx_farch_magic_event(struct efx_channel *channel, u32 magic)
* The NIC batches TX completion events; the message we receive is of * The NIC batches TX completion events; the message we receive is of
* the form "complete all TX events up to this index". * the form "complete all TX events up to this index".
*/ */
static int static void
efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
{ {
unsigned int tx_ev_desc_ptr; unsigned int tx_ev_desc_ptr;
unsigned int tx_ev_q_label; unsigned int tx_ev_q_label;
struct efx_tx_queue *tx_queue; struct efx_tx_queue *tx_queue;
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
int tx_packets = 0;
if (unlikely(READ_ONCE(efx->reset_pending))) if (unlikely(READ_ONCE(efx->reset_pending)))
return 0; return;
if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
/* Transmit completion */ /* Transmit completion */
...@@ -836,8 +835,6 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -836,8 +835,6 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
tx_queue = efx_channel_get_tx_queue( tx_queue = efx_channel_get_tx_queue(
channel, tx_ev_q_label % EFX_TXQ_TYPES); channel, tx_ev_q_label % EFX_TXQ_TYPES);
tx_packets = ((tx_ev_desc_ptr - tx_queue->read_count) &
tx_queue->ptr_mask);
efx_xmit_done(tx_queue, tx_ev_desc_ptr); efx_xmit_done(tx_queue, tx_ev_desc_ptr);
} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
/* Rewrite the FIFO write pointer */ /* Rewrite the FIFO write pointer */
...@@ -856,8 +853,6 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -856,8 +853,6 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
EFX_QWORD_FMT"\n", channel->channel, EFX_QWORD_FMT"\n", channel->channel,
EFX_QWORD_VAL(*event)); EFX_QWORD_VAL(*event));
} }
return tx_packets;
} }
/* Detect errors included in the rx_evt_pkt_ok bit. */ /* Detect errors included in the rx_evt_pkt_ok bit. */
...@@ -1090,7 +1085,7 @@ efx_farch_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event) ...@@ -1090,7 +1085,7 @@ efx_farch_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
int qid; int qid;
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) { if (qid < EFX_TXQ_TYPES * (efx->n_tx_channels + efx->n_extra_tx_channels)) {
tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES, tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES,
qid % EFX_TXQ_TYPES); qid % EFX_TXQ_TYPES);
if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) { if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) {
...@@ -1270,7 +1265,6 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget) ...@@ -1270,7 +1265,6 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
unsigned int read_ptr; unsigned int read_ptr;
efx_qword_t event, *p_event; efx_qword_t event, *p_event;
int ev_code; int ev_code;
int tx_packets = 0;
int spent = 0; int spent = 0;
if (budget <= 0) if (budget <= 0)
...@@ -1304,12 +1298,7 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget) ...@@ -1304,12 +1298,7 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
goto out; goto out;
break; break;
case FSE_AZ_EV_CODE_TX_EV: case FSE_AZ_EV_CODE_TX_EV:
tx_packets += efx_farch_handle_tx_event(channel, efx_farch_handle_tx_event(channel, &event);
&event);
if (tx_packets > efx->txq_entries) {
spent = budget;
goto out;
}
break; break;
case FSE_AZ_EV_CODE_DRV_GEN_EV: case FSE_AZ_EV_CODE_DRV_GEN_EV:
efx_farch_handle_generated_event(channel, &event); efx_farch_handle_generated_event(channel, &event);
...@@ -1680,20 +1669,21 @@ void efx_farch_rx_pull_indir_table(struct efx_nic *efx) ...@@ -1680,20 +1669,21 @@ void efx_farch_rx_pull_indir_table(struct efx_nic *efx)
*/ */
void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw) void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
{ {
unsigned vi_count, buftbl_min; unsigned vi_count, buftbl_min, total_tx_channels;
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
struct siena_nic_data *nic_data = efx->nic_data; struct siena_nic_data *nic_data = efx->nic_data;
#endif #endif
total_tx_channels = efx->n_tx_channels + efx->n_extra_tx_channels;
/* Account for the buffer table entries backing the datapath channels /* Account for the buffer table entries backing the datapath channels
* and the descriptor caches for those channels. * and the descriptor caches for those channels.
*/ */
buftbl_min = ((efx->n_rx_channels * EFX_MAX_DMAQ_SIZE + buftbl_min = ((efx->n_rx_channels * EFX_MAX_DMAQ_SIZE +
efx->n_tx_channels * EFX_TXQ_TYPES * EFX_MAX_DMAQ_SIZE + total_tx_channels * EFX_TXQ_TYPES * EFX_MAX_DMAQ_SIZE +
efx->n_channels * EFX_MAX_EVQ_SIZE) efx->n_channels * EFX_MAX_EVQ_SIZE)
* sizeof(efx_qword_t) / EFX_BUF_SIZE); * sizeof(efx_qword_t) / EFX_BUF_SIZE);
vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); vi_count = max(efx->n_channels, total_tx_channels * EFX_TXQ_TYPES);
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
if (efx->type->sriov_wanted) { if (efx->type->sriov_wanted) {
......
...@@ -191,6 +191,7 @@ struct efx_tx_buffer { ...@@ -191,6 +191,7 @@ struct efx_tx_buffer {
* Size of the region is efx_piobuf_size. * Size of the region is efx_piobuf_size.
* @piobuf_offset: Buffer offset to be specified in PIO descriptors * @piobuf_offset: Buffer offset to be specified in PIO descriptors
* @initialised: Has hardware queue been initialised? * @initialised: Has hardware queue been initialised?
* @timestamping: Is timestamping enabled for this channel?
* @handle_tso: TSO xmit preparation handler. Sets up the TSO metadata and * @handle_tso: TSO xmit preparation handler. Sets up the TSO metadata and
* may also map tx data, depending on the nature of the TSO implementation. * may also map tx data, depending on the nature of the TSO implementation.
* @read_count: Current read pointer. * @read_count: Current read pointer.
...@@ -202,6 +203,10 @@ struct efx_tx_buffer { ...@@ -202,6 +203,10 @@ struct efx_tx_buffer {
* avoid cache-line ping-pong between the xmit path and the * avoid cache-line ping-pong between the xmit path and the
* completion path. * completion path.
* @merge_events: Number of TX merged completion events * @merge_events: Number of TX merged completion events
* @completed_desc_ptr: Most recent completed pointer - only used with
* timestamping.
* @completed_timestamp_major: Top part of the most recent tx timestamp.
* @completed_timestamp_minor: Low part of the most recent tx timestamp.
* @insert_count: Current insert pointer * @insert_count: Current insert pointer
* This is the number of buffers that have been added to the * This is the number of buffers that have been added to the
* software ring. * software ring.
...@@ -247,6 +252,7 @@ struct efx_tx_queue { ...@@ -247,6 +252,7 @@ struct efx_tx_queue {
void __iomem *piobuf; void __iomem *piobuf;
unsigned int piobuf_offset; unsigned int piobuf_offset;
bool initialised; bool initialised;
bool timestamping;
/* Function pointers used in the fast path. */ /* Function pointers used in the fast path. */
int (*handle_tso)(struct efx_tx_queue*, struct sk_buff*, bool *); int (*handle_tso)(struct efx_tx_queue*, struct sk_buff*, bool *);
...@@ -257,6 +263,9 @@ struct efx_tx_queue { ...@@ -257,6 +263,9 @@ struct efx_tx_queue {
unsigned int merge_events; unsigned int merge_events;
unsigned int bytes_compl; unsigned int bytes_compl;
unsigned int pkts_compl; unsigned int pkts_compl;
unsigned int completed_desc_ptr;
u32 completed_timestamp_major;
u32 completed_timestamp_minor;
/* Members used only on the xmit path */ /* Members used only on the xmit path */
unsigned int insert_count ____cacheline_aligned_in_smp; unsigned int insert_count ____cacheline_aligned_in_smp;
...@@ -522,8 +531,12 @@ struct efx_msi_context { ...@@ -522,8 +531,12 @@ struct efx_msi_context {
* @copy: Copy the channel state prior to reallocation. May be %NULL if * @copy: Copy the channel state prior to reallocation. May be %NULL if
* reallocation is not supported. * reallocation is not supported.
* @receive_skb: Handle an skb ready to be passed to netif_receive_skb() * @receive_skb: Handle an skb ready to be passed to netif_receive_skb()
* @want_txqs: Determine whether this channel should have TX queues
* created. If %NULL, TX queues are not created.
* @keep_eventq: Flag for whether event queue should be kept initialised * @keep_eventq: Flag for whether event queue should be kept initialised
* while the device is stopped * while the device is stopped
* @want_pio: Flag for whether PIO buffers should be linked to this
* channel's TX queues.
*/ */
struct efx_channel_type { struct efx_channel_type {
void (*handle_no_channel)(struct efx_nic *); void (*handle_no_channel)(struct efx_nic *);
...@@ -532,7 +545,9 @@ struct efx_channel_type { ...@@ -532,7 +545,9 @@ struct efx_channel_type {
void (*get_name)(struct efx_channel *, char *buf, size_t len); void (*get_name)(struct efx_channel *, char *buf, size_t len);
struct efx_channel *(*copy)(const struct efx_channel *); struct efx_channel *(*copy)(const struct efx_channel *);
bool (*receive_skb)(struct efx_channel *, struct sk_buff *); bool (*receive_skb)(struct efx_channel *, struct sk_buff *);
bool (*want_txqs)(struct efx_channel *);
bool keep_eventq; bool keep_eventq;
bool want_pio;
}; };
enum efx_led_mode { enum efx_led_mode {
...@@ -735,6 +750,7 @@ struct vfdi_status; ...@@ -735,6 +750,7 @@ struct vfdi_status;
* @n_channels: Number of channels in use * @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues) * @n_rx_channels: Number of channels used for RX (= number of RX queues)
* @n_tx_channels: Number of channels used for TX * @n_tx_channels: Number of channels used for TX
* @n_extra_tx_channels: Number of extra channels with TX queues
* @rx_ip_align: RX DMA address offset to have IP header aligned in * @rx_ip_align: RX DMA address offset to have IP header aligned in
* in accordance with NET_IP_ALIGN * in accordance with NET_IP_ALIGN
* @rx_dma_len: Current maximum RX DMA length * @rx_dma_len: Current maximum RX DMA length
...@@ -881,6 +897,7 @@ struct efx_nic { ...@@ -881,6 +897,7 @@ struct efx_nic {
unsigned rss_spread; unsigned rss_spread;
unsigned tx_channel_offset; unsigned tx_channel_offset;
unsigned n_tx_channels; unsigned n_tx_channels;
unsigned n_extra_tx_channels;
unsigned int rx_ip_align; unsigned int rx_ip_align;
unsigned int rx_dma_len; unsigned int rx_dma_len;
unsigned int rx_buffer_order; unsigned int rx_buffer_order;
...@@ -1363,8 +1380,8 @@ efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) ...@@ -1363,8 +1380,8 @@ efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
static inline bool efx_channel_has_tx_queues(struct efx_channel *channel) static inline bool efx_channel_has_tx_queues(struct efx_channel *channel)
{ {
return channel->channel - channel->efx->tx_channel_offset < return channel->type && channel->type->want_txqs &&
channel->efx->n_tx_channels; channel->type->want_txqs(channel);
} }
static inline struct efx_tx_queue * static inline struct efx_tx_queue *
......
...@@ -440,6 +440,7 @@ struct efx_ef10_nic_data { ...@@ -440,6 +440,7 @@ struct efx_ef10_nic_data {
struct efx_udp_tunnel udp_tunnels[16]; struct efx_udp_tunnel udp_tunnels[16];
bool udp_tunnels_dirty; bool udp_tunnels_dirty;
struct mutex udp_tunnels_lock; struct mutex udp_tunnels_lock;
u64 licensed_features;
}; };
int efx_init_sriov(void); int efx_init_sriov(void);
...@@ -448,6 +449,7 @@ void efx_fini_sriov(void); ...@@ -448,6 +449,7 @@ void efx_fini_sriov(void);
struct ethtool_ts_info; struct ethtool_ts_info;
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel); int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
void efx_ptp_defer_probe_with_channel(struct efx_nic *efx); void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
struct efx_channel *efx_ptp_channel(struct efx_nic *efx);
void efx_ptp_remove(struct efx_nic *efx); void efx_ptp_remove(struct efx_nic *efx);
int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr); int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr); int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
...@@ -471,6 +473,8 @@ static inline void efx_rx_skb_attach_timestamp(struct efx_channel *channel, ...@@ -471,6 +473,8 @@ static inline void efx_rx_skb_attach_timestamp(struct efx_channel *channel,
} }
void efx_ptp_start_datapath(struct efx_nic *efx); void efx_ptp_start_datapath(struct efx_nic *efx);
void efx_ptp_stop_datapath(struct efx_nic *efx); void efx_ptp_stop_datapath(struct efx_nic *efx);
bool efx_ptp_use_mac_tx_timestamps(struct efx_nic *efx);
ktime_t efx_ptp_nic_to_kernel_time(struct efx_tx_queue *tx_queue);
extern const struct efx_nic_type falcon_a1_nic_type; extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type; extern const struct efx_nic_type falcon_b0_nic_type;
......
This diff is collapsed.
...@@ -77,9 +77,23 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, ...@@ -77,9 +77,23 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
} }
if (buffer->flags & EFX_TX_BUF_SKB) { if (buffer->flags & EFX_TX_BUF_SKB) {
struct sk_buff *skb = (struct sk_buff *)buffer->skb;
EFX_WARN_ON_PARANOID(!pkts_compl || !bytes_compl); EFX_WARN_ON_PARANOID(!pkts_compl || !bytes_compl);
(*pkts_compl)++; (*pkts_compl)++;
(*bytes_compl) += buffer->skb->len; (*bytes_compl) += skb->len;
if (tx_queue->timestamping &&
(tx_queue->completed_timestamp_major ||
tx_queue->completed_timestamp_minor)) {
struct skb_shared_hwtstamps hwtstamp;
hwtstamp.hwtstamp =
efx_ptp_nic_to_kernel_time(tx_queue);
skb_tstamp_tx(skb, &hwtstamp);
tx_queue->completed_timestamp_major = 0;
tx_queue->completed_timestamp_minor = 0;
}
dev_consume_skb_any((struct sk_buff *)buffer->skb); dev_consume_skb_any((struct sk_buff *)buffer->skb);
netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev, netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev,
"TX queue %d transmission id %x complete\n", "TX queue %d transmission id %x complete\n",
...@@ -828,6 +842,11 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) ...@@ -828,6 +842,11 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
tx_queue->old_read_count = 0; tx_queue->old_read_count = 0;
tx_queue->empty_read_count = 0 | EFX_EMPTY_COUNT_VALID; tx_queue->empty_read_count = 0 | EFX_EMPTY_COUNT_VALID;
tx_queue->xmit_more_available = false; tx_queue->xmit_more_available = false;
tx_queue->timestamping = (efx_ptp_use_mac_tx_timestamps(efx) &&
tx_queue->channel == efx_ptp_channel(efx));
tx_queue->completed_desc_ptr = tx_queue->ptr_mask;
tx_queue->completed_timestamp_major = 0;
tx_queue->completed_timestamp_minor = 0;
/* Set up default function pointers. These may get replaced by /* Set up default function pointers. These may get replaced by
* efx_nic_init_tx() based off NIC/queue capabilities. * efx_nic_init_tx() based off NIC/queue capabilities.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment