Commit 82faa9b7 authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by Jeff Kirsher

igc: Add support for ETF offloading

This adds support for ETF offloading for the i225 controller.

For i225, the LaunchTime feature is almost a subset of the Qbv
feature. The main change from the i210 is that the launchtime of each
packet is specified as an offset applied to the BASET register. BASET
is automatically incremented each cycle.

For i225, the approach chosen is to re-use most of the setup used for
taprio offloading. With a few changes:

 - The more or less obvious one is that when ETF is enabled, we should
 set add the expected launchtime to the (advanced) transmit
 descriptor;

 - The less obvious, is that when taprio offloading is not enabled, we
 add a dummy schedule (all queues are open all the time, with a cycle
 time of 1 second).
Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: default avatarAndre Guedes <andre.guedes@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent ec50a9d4
...@@ -440,6 +440,7 @@ ...@@ -440,6 +440,7 @@
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001 #define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008 #define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002 #define IGC_TXQCTL_STRICT_CYCLE 0x00000002
#define IGC_TXQCTL_STRICT_END 0x00000004 #define IGC_TXQCTL_STRICT_END 0x00000004
......
...@@ -869,6 +869,23 @@ static int igc_write_mc_addr_list(struct net_device *netdev) ...@@ -869,6 +869,23 @@ static int igc_write_mc_addr_list(struct net_device *netdev)
return netdev_mc_count(netdev); return netdev_mc_count(netdev);
} }
static __le32 igc_tx_launchtime(struct igc_adapter *adapter, ktime_t txtime)
{
ktime_t cycle_time = adapter->cycle_time;
ktime_t base_time = adapter->base_time;
u32 launchtime;
/* FIXME: when using ETF together with taprio, we may have a
* case where 'delta' is larger than the cycle_time, this may
* cause problems if we don't read the current value of
* IGC_BASET, as the value writen into the launchtime
* descriptor field may be misinterpreted.
*/
div_s64_rem(ktime_sub_ns(txtime, base_time), cycle_time, &launchtime);
return cpu_to_le32(launchtime);
}
static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
struct igc_tx_buffer *first, struct igc_tx_buffer *first,
u32 vlan_macip_lens, u32 type_tucmd, u32 vlan_macip_lens, u32 type_tucmd,
...@@ -876,7 +893,6 @@ static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, ...@@ -876,7 +893,6 @@ static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
{ {
struct igc_adv_tx_context_desc *context_desc; struct igc_adv_tx_context_desc *context_desc;
u16 i = tx_ring->next_to_use; u16 i = tx_ring->next_to_use;
struct timespec64 ts;
context_desc = IGC_TX_CTXTDESC(tx_ring, i); context_desc = IGC_TX_CTXTDESC(tx_ring, i);
...@@ -898,9 +914,12 @@ static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, ...@@ -898,9 +914,12 @@ static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
* should have been handled by the upper layers. * should have been handled by the upper layers.
*/ */
if (tx_ring->launchtime_enable) { if (tx_ring->launchtime_enable) {
ts = ktime_to_timespec64(first->skb->tstamp); struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
ktime_t txtime = first->skb->tstamp;
first->skb->tstamp = ktime_set(0, 0); first->skb->tstamp = ktime_set(0, 0);
context_desc->launch_time = cpu_to_le32(ts.tv_nsec / 32); context_desc->launch_time = igc_tx_launchtime(adapter,
txtime);
} else { } else {
context_desc->launch_time = 0; context_desc->launch_time = 0;
} }
...@@ -4496,6 +4515,32 @@ static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ...@@ -4496,6 +4515,32 @@ static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
} }
} }
static int igc_save_launchtime_params(struct igc_adapter *adapter, int queue,
bool enable)
{
struct igc_ring *ring;
int i;
if (queue < 0 || queue >= adapter->num_tx_queues)
return -EINVAL;
ring = adapter->tx_ring[queue];
ring->launchtime_enable = enable;
if (adapter->base_time)
return 0;
adapter->cycle_time = NSEC_PER_SEC;
for (i = 0; i < adapter->num_tx_queues; i++) {
ring = adapter->tx_ring[i];
ring->start_time = 0;
ring->end_time = NSEC_PER_SEC;
}
return 0;
}
static bool validate_schedule(const struct tc_taprio_qopt_offload *qopt) static bool validate_schedule(const struct tc_taprio_qopt_offload *qopt)
{ {
int queue_uses[IGC_MAX_TX_QUEUES] = { }; int queue_uses[IGC_MAX_TX_QUEUES] = { };
...@@ -4528,6 +4573,22 @@ static bool validate_schedule(const struct tc_taprio_qopt_offload *qopt) ...@@ -4528,6 +4573,22 @@ static bool validate_schedule(const struct tc_taprio_qopt_offload *qopt)
return true; return true;
} }
static int igc_tsn_enable_launchtime(struct igc_adapter *adapter,
struct tc_etf_qopt_offload *qopt)
{
struct igc_hw *hw = &adapter->hw;
int err;
if (hw->mac.type != igc_i225)
return -EOPNOTSUPP;
err = igc_save_launchtime_params(adapter, qopt->queue, qopt->enable);
if (err)
return err;
return igc_tsn_offload_apply(adapter);
}
static int igc_save_qbv_schedule(struct igc_adapter *adapter, static int igc_save_qbv_schedule(struct igc_adapter *adapter,
struct tc_taprio_qopt_offload *qopt) struct tc_taprio_qopt_offload *qopt)
{ {
...@@ -4598,6 +4659,9 @@ static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type, ...@@ -4598,6 +4659,9 @@ static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_TAPRIO: case TC_SETUP_QDISC_TAPRIO:
return igc_tsn_enable_qbv_scheduling(adapter, type_data); return igc_tsn_enable_qbv_scheduling(adapter, type_data);
case TC_SETUP_QDISC_ETF:
return igc_tsn_enable_launchtime(adapter, type_data);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -4,6 +4,20 @@ ...@@ -4,6 +4,20 @@
#include "igc.h" #include "igc.h"
#include "igc_tsn.h" #include "igc_tsn.h"
static bool is_any_launchtime(struct igc_adapter *adapter)
{
int i;
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *ring = adapter->tx_ring[i];
if (ring->launchtime_enable)
return true;
}
return false;
}
/* Returns the TSN specific registers to their default values after /* Returns the TSN specific registers to their default values after
* TSN offloading is disabled. * TSN offloading is disabled.
*/ */
...@@ -88,6 +102,9 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) ...@@ -88,6 +102,9 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
IGC_TXQCTL_STRICT_END; IGC_TXQCTL_STRICT_END;
} }
if (ring->launchtime_enable)
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
wr32(IGC_TXQCTL(i), txqctl); wr32(IGC_TXQCTL(i), txqctl);
} }
...@@ -115,7 +132,7 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter) ...@@ -115,7 +132,7 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
int igc_tsn_offload_apply(struct igc_adapter *adapter) int igc_tsn_offload_apply(struct igc_adapter *adapter)
{ {
bool is_any_enabled = adapter->base_time; bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter);
if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled) if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled)
return 0; return 0;
......
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