Commit 0d08c9ec authored by Po Liu's avatar Po Liu Committed by David S. Miller

enetc: add support time specific departure base on the qos etf

ENETC implement time specific departure capability, which enables
the user to specify when a frame can be transmitted. When this
capability is enabled, the device will delay the transmission of
the frame so that it can be transmitted at the precisely specified time.
The delay departure time up to 0.5 seconds in the future. If the
departure time in the transmit BD has not yet been reached, based
on the current time, the packet will not be transmitted.

This driver was loaded by Qos driver ETF. User could load it by tc
commands. Here are the example commands:

tc qdisc add dev eth0 root handle 1: mqprio \
	   num_tc 8 map 0 1 2 3 4 5 6 7 hw 1
tc qdisc replace dev eth0 parent 1:8 etf \
	   clockid CLOCK_TAI delta 30000  offload

These example try to set queue mapping first and then set queue 7
with 30us ahead dequeue time.

Then user send test frame should set SO_TXTIME feature for socket.

There are also some limitations for this feature in hardware:
- Transmit checksum offloads and time specific departure operation
are mutually exclusive.
- Time Aware Shaper feature (Qbv) offload and time specific departure
operation are mutually exclusive.
Signed-off-by: default avatarPo Liu <Po.Liu@nxp.com>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a02158d6
...@@ -149,11 +149,21 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb, ...@@ -149,11 +149,21 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
if (enetc_tx_csum(skb, &temp_bd)) if (enetc_tx_csum(skb, &temp_bd))
flags |= ENETC_TXBD_FLAGS_CSUM | ENETC_TXBD_FLAGS_L4CS; flags |= ENETC_TXBD_FLAGS_CSUM | ENETC_TXBD_FLAGS_L4CS;
else if (tx_ring->tsd_enable)
flags |= ENETC_TXBD_FLAGS_TSE | ENETC_TXBD_FLAGS_TXSTART;
/* first BD needs frm_len and offload flags set */ /* first BD needs frm_len and offload flags set */
temp_bd.frm_len = cpu_to_le16(skb->len); temp_bd.frm_len = cpu_to_le16(skb->len);
temp_bd.flags = flags; temp_bd.flags = flags;
if (flags & ENETC_TXBD_FLAGS_TSE) {
u32 temp;
temp = (skb->skb_mstamp_ns >> 5 & ENETC_TXBD_TXSTART_MASK)
| (flags << ENETC_TXBD_FLAGS_OFFSET);
temp_bd.txstart = cpu_to_le32(temp);
}
if (flags & ENETC_TXBD_FLAGS_EX) { if (flags & ENETC_TXBD_FLAGS_EX) {
u8 e_flags = 0; u8 e_flags = 0;
*txbd = temp_bd; *txbd = temp_bd;
...@@ -1505,6 +1515,8 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, ...@@ -1505,6 +1515,8 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
return enetc_setup_tc_taprio(ndev, type_data); return enetc_setup_tc_taprio(ndev, type_data);
case TC_SETUP_QDISC_CBS: case TC_SETUP_QDISC_CBS:
return enetc_setup_tc_cbs(ndev, type_data); return enetc_setup_tc_cbs(ndev, type_data);
case TC_SETUP_QDISC_ETF:
return enetc_setup_tc_txtime(ndev, type_data);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -72,6 +72,7 @@ struct enetc_bdr { ...@@ -72,6 +72,7 @@ struct enetc_bdr {
struct enetc_ring_stats stats; struct enetc_ring_stats stats;
dma_addr_t bd_dma_base; dma_addr_t bd_dma_base;
u8 tsd_enable; /* Time specific departure */
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
static inline void enetc_bdr_idx_inc(struct enetc_bdr *bdr, int *i) static inline void enetc_bdr_idx_inc(struct enetc_bdr *bdr, int *i)
...@@ -256,8 +257,10 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd); ...@@ -256,8 +257,10 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data); int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
void enetc_sched_speed_set(struct net_device *ndev); void enetc_sched_speed_set(struct net_device *ndev);
int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data); int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
int enetc_setup_tc_txtime(struct net_device *ndev, void *type_data);
#else #else
#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
#define enetc_sched_speed_set(ndev) (void)0 #define enetc_sched_speed_set(ndev) (void)0
#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP #define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
#define enetc_setup_tc_txtime(ndev, type_data) -EOPNOTSUPP
#endif #endif
...@@ -358,6 +358,7 @@ union enetc_tx_bd { ...@@ -358,6 +358,7 @@ union enetc_tx_bd {
u8 l4_csoff; u8 l4_csoff;
u8 flags; u8 flags;
}; /* default layout */ }; /* default layout */
__le32 txstart;
__le32 lstatus; __le32 lstatus;
}; };
}; };
...@@ -378,11 +379,14 @@ union enetc_tx_bd { ...@@ -378,11 +379,14 @@ union enetc_tx_bd {
}; };
#define ENETC_TXBD_FLAGS_L4CS BIT(0) #define ENETC_TXBD_FLAGS_L4CS BIT(0)
#define ENETC_TXBD_FLAGS_TSE BIT(1)
#define ENETC_TXBD_FLAGS_W BIT(2) #define ENETC_TXBD_FLAGS_W BIT(2)
#define ENETC_TXBD_FLAGS_CSUM BIT(3) #define ENETC_TXBD_FLAGS_CSUM BIT(3)
#define ENETC_TXBD_FLAGS_TXSTART BIT(4)
#define ENETC_TXBD_FLAGS_EX BIT(6) #define ENETC_TXBD_FLAGS_EX BIT(6)
#define ENETC_TXBD_FLAGS_F BIT(7) #define ENETC_TXBD_FLAGS_F BIT(7)
#define ENETC_TXBD_TXSTART_MASK GENMASK(24, 0)
#define ENETC_TXBD_FLAGS_OFFSET 24
static inline void enetc_clear_tx_bd(union enetc_tx_bd *txbd) static inline void enetc_clear_tx_bd(union enetc_tx_bd *txbd)
{ {
memset(txbd, 0, sizeof(*txbd)); memset(txbd, 0, sizeof(*txbd));
...@@ -615,3 +619,7 @@ struct enetc_cbd { ...@@ -615,3 +619,7 @@ struct enetc_cbd {
/* Port time gating capability register */ /* Port time gating capability register */
#define ENETC_QBV_PTGCAPR_OFFSET 0x11a08 #define ENETC_QBV_PTGCAPR_OFFSET 0x11a08
#define ENETC_QBV_MAX_GCL_LEN_MASK GENMASK(15, 0) #define ENETC_QBV_MAX_GCL_LEN_MASK GENMASK(15, 0)
/* Port time specific departure */
#define ENETC_PTCTSDR(n) (0x1210 + 4 * (n))
#define ENETC_TSDE BIT(31)
...@@ -156,6 +156,11 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) ...@@ -156,6 +156,11 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
int err; int err;
int i; int i;
/* TSD and Qbv are mutually exclusive in hardware */
for (i = 0; i < priv->num_tx_rings; i++)
if (priv->tx_ring[i]->tsd_enable)
return -EBUSY;
for (i = 0; i < priv->num_tx_rings; i++) for (i = 0; i < priv->num_tx_rings; i++)
enetc_set_bdr_prio(&priv->si->hw, enetc_set_bdr_prio(&priv->si->hw,
priv->tx_ring[i]->index, priv->tx_ring[i]->index,
...@@ -297,3 +302,33 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) ...@@ -297,3 +302,33 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
return 0; return 0;
} }
int enetc_setup_tc_txtime(struct net_device *ndev, void *type_data)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct tc_etf_qopt_offload *qopt = type_data;
u8 tc_nums = netdev_get_num_tc(ndev);
int tc;
if (!tc_nums)
return -EOPNOTSUPP;
tc = qopt->queue;
if (tc < 0 || tc > priv->num_tx_rings)
return -EINVAL;
/* Do not support TXSTART and TX CSUM offload simutaniously */
if (ndev->features & NETIF_F_CSUM_MASK)
return -EBUSY;
/* TSD and Qbv are mutually exclusive in hardware */
if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE)
return -EBUSY;
priv->tx_ring[tc]->tsd_enable = qopt->enable;
enetc_port_wr(&priv->si->hw, ENETC_PTCTSDR(tc),
qopt->enable ? ENETC_TSDE : 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