summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/igc/igc_tsn.c
diff options
context:
space:
mode:
authorKurt Kanzenbach <kurt@linutronix.de>2024-06-21 09:25:55 +0200
committerTony Nguyen <anthony.l.nguyen@intel.com>2024-08-30 07:33:46 -0700
commit9f3297511dae19b28b333134cbf7e8746722d6a5 (patch)
treeed7831a7e2a08ca0fc20eb4c37cf0a1c6704c1df /drivers/net/ethernet/intel/igc/igc_tsn.c
parentfbdaffe41adca26cb9566e92060b97cd6dd87b60 (diff)
igc: Add MQPRIO offload support
Add support for offloading MQPRIO. The hardware has four priorities as well as four queues. Each queue must be a assigned with a unique priority. However, the priorities are only considered in TSN Tx mode. There are two TSN Tx modes. In case of MQPRIO the Qbv capability is not required. Therefore, use the legacy TSN Tx mode, which performs strict priority arbitration. Example for mqprio with hardware offload: |tc qdisc replace dev ${INTERFACE} handle 100 parent root mqprio num_tc 4 \ | map 0 0 0 0 0 1 2 3 0 0 0 0 0 0 0 0 \ | queues 1@0 1@1 1@2 1@3 \ | hw 1 The mqprio Qdisc also allows to configure the `preemptible_tcs'. However, frame preemption is not supported yet. Tested on Intel i225 and implemented by following data sheet section 7.5.2, Transmit Scheduling. Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de> Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com> Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com> Reviewed-by: Simon Horman <horms@kernel.org> Tested-by: Mor Bar-Gabay <morx.bar.gabay@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_tsn.c')
-rw-r--r--drivers/net/ethernet/intel/igc/igc_tsn.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c
index d68fa7f3d5f0..1e44374ca1ff 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.c
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
@@ -46,6 +46,9 @@ static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
if (is_cbs_enabled(adapter))
new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
+ if (adapter->strict_priority_enable)
+ new_flags |= IGC_FLAG_TSN_LEGACY_ENABLED;
+
return new_flags;
}
@@ -102,11 +105,32 @@ bool igc_tsn_is_taprio_activated_by_user(struct igc_adapter *adapter)
adapter->taprio_offload_enable;
}
+static void igc_tsn_tx_arb(struct igc_adapter *adapter, u16 *queue_per_tc)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 txarb;
+
+ txarb = rd32(IGC_TXARB);
+
+ txarb &= ~(IGC_TXARB_TXQ_PRIO_0_MASK |
+ IGC_TXARB_TXQ_PRIO_1_MASK |
+ IGC_TXARB_TXQ_PRIO_2_MASK |
+ IGC_TXARB_TXQ_PRIO_3_MASK);
+
+ txarb |= IGC_TXARB_TXQ_PRIO_0(queue_per_tc[3]);
+ txarb |= IGC_TXARB_TXQ_PRIO_1(queue_per_tc[2]);
+ txarb |= IGC_TXARB_TXQ_PRIO_2(queue_per_tc[1]);
+ txarb |= IGC_TXARB_TXQ_PRIO_3(queue_per_tc[0]);
+
+ wr32(IGC_TXARB, txarb);
+}
+
/* Returns the TSN specific registers to their default values after
* the adapter is reset.
*/
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
{
+ u16 queue_per_tc[4] = { 3, 2, 1, 0 };
struct igc_hw *hw = &adapter->hw;
u32 tqavctrl;
int i;
@@ -133,7 +157,16 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)
wr32(IGC_QBVCYCLET_S, 0);
wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
+ /* Reset mqprio TC configuration. */
+ netdev_reset_tc(adapter->netdev);
+
+ /* Restore the default Tx arbitration: Priority 0 has the highest
+ * priority and is assigned to queue 0 and so on and so forth.
+ */
+ igc_tsn_tx_arb(adapter, queue_per_tc);
+
adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
+ adapter->flags &= ~IGC_FLAG_TSN_LEGACY_ENABLED;
return 0;
}
@@ -172,6 +205,40 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
if (igc_is_device_id_i226(hw))
igc_tsn_set_retx_qbvfullthreshold(adapter);
+ if (adapter->strict_priority_enable) {
+ int err;
+
+ err = netdev_set_num_tc(adapter->netdev, adapter->num_tc);
+ if (err)
+ return err;
+
+ for (i = 0; i < adapter->num_tc; i++) {
+ err = netdev_set_tc_queue(adapter->netdev, i, 1,
+ adapter->queue_per_tc[i]);
+ if (err)
+ return err;
+ }
+
+ /* In case the card is configured with less than four queues. */
+ for (; i < IGC_MAX_TX_QUEUES; i++)
+ adapter->queue_per_tc[i] = i;
+
+ /* Configure queue priorities according to the user provided
+ * mapping.
+ */
+ igc_tsn_tx_arb(adapter, adapter->queue_per_tc);
+
+ /* Enable legacy TSN mode which will do strict priority without
+ * any other TSN features.
+ */
+ tqavctrl = rd32(IGC_TQAVCTRL);
+ tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN;
+ tqavctrl &= ~IGC_TQAVCTRL_ENHANCED_QAV;
+ wr32(IGC_TQAVCTRL, tqavctrl);
+
+ return 0;
+ }
+
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *ring = adapter->tx_ring[i];
u32 txqctl = 0;