Skip to content

Commit 8271453

Browse files
vladimirolteankuba-moo
authored andcommitted
net: enetc: only commit preemptible TCs to hardware when MM TX is active
This was left as TODO in commit 01e23b2 ("net: enetc: add support for preemptible traffic classes") since it's relatively complicated. Where this makes a difference is with a configuration as follows: ethtool --set-mm eno0 pmac-enabled on tx-enabled on verify-enabled on Preemptible packets should only be sent when the MAC Merge TX direction becomes active (i.o.w. when the verification process succeeds, aka when the link partner confirms it can process preemptible traffic). But the tc qdisc with the preemptible traffic classes is offloaded completely asynchronously w.r.t. the MM becoming active. The ENETC manual does suggest that this should be handled in the driver: "On startup, software should wait for the verification process to complete (MMCSR[VSTS]=011) before initiating traffic". Adding the necessary logic allows future selftests to uphold the claim that an inactive or disabled MAC Merge layer should never send data packets through the pMAC. This change moves enetc_set_ptcfpr() from enetc.c to enetc_ethtool.c, where its only caller is now - enetc_mm_commit_preemptible_tcs(). Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 153b5b1 commit 8271453

File tree

4 files changed

+75
-18
lines changed

4 files changed

+75
-18
lines changed

drivers/net/ethernet/freescale/enetc/enetc.c

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,12 @@ void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val)
2525
}
2626
EXPORT_SYMBOL_GPL(enetc_port_mac_wr);
2727

28-
void enetc_set_ptcfpr(struct enetc_hw *hw, unsigned long preemptible_tcs)
28+
static void enetc_change_preemptible_tcs(struct enetc_ndev_priv *priv,
29+
u8 preemptible_tcs)
2930
{
30-
u32 val;
31-
int tc;
32-
33-
for (tc = 0; tc < 8; tc++) {
34-
val = enetc_port_rd(hw, ENETC_PTCFPR(tc));
35-
36-
if (preemptible_tcs & BIT(tc))
37-
val |= ENETC_PTCFPR_FPE;
38-
else
39-
val &= ~ENETC_PTCFPR_FPE;
40-
41-
enetc_port_wr(hw, ENETC_PTCFPR(tc), val);
42-
}
31+
priv->preemptible_tcs = preemptible_tcs;
32+
enetc_mm_commit_preemptible_tcs(priv);
4333
}
44-
EXPORT_SYMBOL_GPL(enetc_set_ptcfpr);
4534

4635
static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
4736
{
@@ -2659,7 +2648,7 @@ static void enetc_reset_tc_mqprio(struct net_device *ndev)
26592648

26602649
enetc_debug_tx_ring_prios(priv);
26612650

2662-
enetc_set_ptcfpr(hw, 0);
2651+
enetc_change_preemptible_tcs(priv, 0);
26632652
}
26642653

26652654
int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
@@ -2714,7 +2703,7 @@ int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
27142703

27152704
enetc_debug_tx_ring_prios(priv);
27162705

2717-
enetc_set_ptcfpr(hw, mqprio->preemptible_tcs);
2706+
enetc_change_preemptible_tcs(priv, mqprio->preemptible_tcs);
27182707

27192708
return 0;
27202709

drivers/net/ethernet/freescale/enetc/enetc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ struct enetc_ndev_priv {
355355
u16 rx_bd_count, tx_bd_count;
356356

357357
u16 msg_enable;
358+
359+
u8 preemptible_tcs;
360+
358361
enum enetc_active_offloads active_offloads;
359362

360363
u32 speed; /* store speed for compare update pspeed */
@@ -433,6 +436,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
433436
/* ethtool */
434437
void enetc_set_ethtool_ops(struct net_device *ndev);
435438
void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link);
439+
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);
436440

437441
/* control buffer descriptor ring (CBDR) */
438442
int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
@@ -486,7 +490,6 @@ static inline void enetc_cbd_free_data_mem(struct enetc_si *si, int size,
486490

487491
void enetc_reset_ptcmsdur(struct enetc_hw *hw);
488492
void enetc_set_ptcmsdur(struct enetc_hw *hw, u32 *queue_max_sdu);
489-
void enetc_set_ptcfpr(struct enetc_hw *hw, unsigned long preemptible_tcs);
490493

491494
#ifdef CONFIG_FSL_ENETC_QOS
492495
int enetc_qos_query_caps(struct net_device *ndev, void *type_data);

drivers/net/ethernet/freescale/enetc/enetc_ethtool.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,64 @@ static int enetc_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
991991
return 0;
992992
}
993993

994+
static int enetc_mm_wait_tx_active(struct enetc_hw *hw, int verify_time)
995+
{
996+
int timeout = verify_time * USEC_PER_MSEC * ENETC_MM_VERIFY_RETRIES;
997+
u32 val;
998+
999+
/* This will time out after the standard value of 3 verification
1000+
* attempts. To not sleep forever, it relies on a non-zero verify_time,
1001+
* guarantee which is provided by the ethtool nlattr policy.
1002+
*/
1003+
return read_poll_timeout(enetc_port_rd, val,
1004+
ENETC_MMCSR_GET_VSTS(val) == 3,
1005+
ENETC_MM_VERIFY_SLEEP_US, timeout,
1006+
true, hw, ENETC_MMCSR);
1007+
}
1008+
1009+
static void enetc_set_ptcfpr(struct enetc_hw *hw, u8 preemptible_tcs)
1010+
{
1011+
u32 val;
1012+
int tc;
1013+
1014+
for (tc = 0; tc < 8; tc++) {
1015+
val = enetc_port_rd(hw, ENETC_PTCFPR(tc));
1016+
1017+
if (preemptible_tcs & BIT(tc))
1018+
val |= ENETC_PTCFPR_FPE;
1019+
else
1020+
val &= ~ENETC_PTCFPR_FPE;
1021+
1022+
enetc_port_wr(hw, ENETC_PTCFPR(tc), val);
1023+
}
1024+
}
1025+
1026+
/* ENETC does not have an IRQ to notify changes to the MAC Merge TX status
1027+
* (active/inactive), but the preemptible traffic classes should only be
1028+
* committed to hardware once TX is active. Resort to polling.
1029+
*/
1030+
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv)
1031+
{
1032+
struct enetc_hw *hw = &priv->si->hw;
1033+
u8 preemptible_tcs = 0;
1034+
u32 val;
1035+
int err;
1036+
1037+
val = enetc_port_rd(hw, ENETC_MMCSR);
1038+
if (!(val & ENETC_MMCSR_ME))
1039+
goto out;
1040+
1041+
if (!(val & ENETC_MMCSR_VDIS)) {
1042+
err = enetc_mm_wait_tx_active(hw, ENETC_MMCSR_GET_VT(val));
1043+
if (err)
1044+
goto out;
1045+
}
1046+
1047+
preemptible_tcs = priv->preemptible_tcs;
1048+
out:
1049+
enetc_set_ptcfpr(hw, preemptible_tcs);
1050+
}
1051+
9941052
/* FIXME: Workaround for the link partner's verification failing if ENETC
9951053
* priorly received too much express traffic. The documentation doesn't
9961054
* suggest this is needed.
@@ -1061,6 +1119,8 @@ static int enetc_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
10611119

10621120
enetc_restart_emac_rx(priv->si);
10631121

1122+
enetc_mm_commit_preemptible_tcs(priv);
1123+
10641124
mutex_unlock(&priv->mm_lock);
10651125

10661126
return 0;
@@ -1094,6 +1154,8 @@ void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link)
10941154

10951155
enetc_port_wr(hw, ENETC_MMCSR, val);
10961156

1157+
enetc_mm_commit_preemptible_tcs(priv);
1158+
10971159
mutex_unlock(&priv->mm_lock);
10981160
}
10991161
EXPORT_SYMBOL_GPL(enetc_mm_link_state_update);

drivers/net/ethernet/freescale/enetc/enetc_hw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include <linux/bitops.h>
55

6+
#define ENETC_MM_VERIFY_SLEEP_US USEC_PER_MSEC
7+
#define ENETC_MM_VERIFY_RETRIES 3
8+
69
/* ENETC device IDs */
710
#define ENETC_DEV_ID_PF 0xe100
811
#define ENETC_DEV_ID_VF 0xef00

0 commit comments

Comments
 (0)