@@ -4528,6 +4528,7 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path);
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
netdev_features_t features);
+struct sk_buff *skb_gso_segment_txtime(struct sk_buff *skb);
struct netdev_bonding_info {
ifslave slave;
@@ -493,7 +493,8 @@ struct sock {
u8 sk_clockid;
u8 sk_txtime_deadline_mode : 1,
sk_txtime_report_errors : 1,
- sk_txtime_unused : 6;
+ sk_txtime_multi_release : 1,
+ sk_txtime_unused : 5;
struct socket *sk_socket;
void *sk_user_data;
@@ -162,8 +162,9 @@ struct scm_ts_pktinfo {
enum txtime_flags {
SOF_TXTIME_DEADLINE_MODE = (1 << 0),
SOF_TXTIME_REPORT_ERRORS = (1 << 1),
+ SOF_TXTIME_MULTI_RELEASE = (1 << 2),
- SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS,
+ SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_MULTI_RELEASE,
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) |
SOF_TXTIME_FLAGS_LAST
};
@@ -3377,6 +3377,50 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
}
EXPORT_SYMBOL(__skb_gso_segment);
+struct sk_buff *skb_gso_segment_txtime(struct sk_buff *skb)
+{
+ int mss_per_ival, mss_in_cur_ival;
+ struct sk_buff *segs, *seg;
+ struct skb_shared_info *sh;
+ u64 step_ns, tstamp;
+
+ if (!skb->sk || !sk_fullsock(skb->sk) ||
+ !skb->sk->sk_txtime_multi_release)
+ return NULL;
+
+ /* extract multi release variables mss and stepsize */
+ mss_per_ival = skb->tstamp & 0xF;
+ step_ns = ((skb->tstamp >> 4) & 0xF) * NSEC_PER_MSEC;
+ tstamp = skb->tstamp;
+
+ if (mss_per_ival == 0)
+ return NULL;
+
+ /* skip multi-release if total segs can be sent at once */
+ sh = skb_shinfo(skb);
+ if (sh->gso_segs <= mss_per_ival)
+ return NULL;
+
+ segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
+ if (IS_ERR_OR_NULL(segs))
+ return segs;
+
+ mss_in_cur_ival = 0;
+
+ for (seg = segs; seg; seg = seg->next) {
+ seg->tstamp = tstamp & ~0xFF;
+
+ mss_in_cur_ival++;
+ if (mss_in_cur_ival == mss_per_ival) {
+ tstamp += step_ns;
+ mss_in_cur_ival = 0;
+ }
+ }
+
+ return segs;
+}
+EXPORT_SYMBOL_GPL(skb_gso_segment_txtime);
+
/* Take action when hardware reception checksum errors are detected. */
#ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev, struct sk_buff *skb)
@@ -1258,6 +1258,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
!!(sk_txtime.flags & SOF_TXTIME_DEADLINE_MODE);
sk->sk_txtime_report_errors =
!!(sk_txtime.flags & SOF_TXTIME_REPORT_ERRORS);
+ sk->sk_txtime_multi_release =
+ !!(sk_txtime.flags & SOF_TXTIME_MULTI_RELEASE);
break;
case SO_BINDTOIFINDEX:
@@ -1608,6 +1610,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
SOF_TXTIME_DEADLINE_MODE : 0;
v.txtime.flags |= sk->sk_txtime_report_errors ?
SOF_TXTIME_REPORT_ERRORS : 0;
+ v.txtime.flags |= sk->sk_txtime_multi_release ?
+ SOF_TXTIME_MULTI_RELEASE : 0;
break;
case SO_BINDTOIFINDEX: