diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/phy/dp83640.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index f99937905bd..be381c24c4b 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c | |||
@@ -761,6 +761,41 @@ static void decode_status_frame(struct dp83640_private *dp83640, | |||
761 | } | 761 | } |
762 | } | 762 | } |
763 | 763 | ||
764 | static int is_sync(struct sk_buff *skb, int type) | ||
765 | { | ||
766 | u8 *data = skb->data, *msgtype; | ||
767 | unsigned int offset = 0; | ||
768 | |||
769 | switch (type) { | ||
770 | case PTP_CLASS_V1_IPV4: | ||
771 | case PTP_CLASS_V2_IPV4: | ||
772 | offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; | ||
773 | break; | ||
774 | case PTP_CLASS_V1_IPV6: | ||
775 | case PTP_CLASS_V2_IPV6: | ||
776 | offset = OFF_PTP6; | ||
777 | break; | ||
778 | case PTP_CLASS_V2_L2: | ||
779 | offset = ETH_HLEN; | ||
780 | break; | ||
781 | case PTP_CLASS_V2_VLAN: | ||
782 | offset = ETH_HLEN + VLAN_HLEN; | ||
783 | break; | ||
784 | default: | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | if (type & PTP_CLASS_V1) | ||
789 | offset += OFF_PTP_CONTROL; | ||
790 | |||
791 | if (skb->len < offset + 1) | ||
792 | return 0; | ||
793 | |||
794 | msgtype = data + offset; | ||
795 | |||
796 | return (*msgtype & 0xf) == 0; | ||
797 | } | ||
798 | |||
764 | static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) | 799 | static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) |
765 | { | 800 | { |
766 | u16 *seqid; | 801 | u16 *seqid; |
@@ -1010,16 +1045,10 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) | |||
1010 | if (cfg.flags) /* reserved for future extensions */ | 1045 | if (cfg.flags) /* reserved for future extensions */ |
1011 | return -EINVAL; | 1046 | return -EINVAL; |
1012 | 1047 | ||
1013 | switch (cfg.tx_type) { | 1048 | if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC) |
1014 | case HWTSTAMP_TX_OFF: | ||
1015 | dp83640->hwts_tx_en = 0; | ||
1016 | break; | ||
1017 | case HWTSTAMP_TX_ON: | ||
1018 | dp83640->hwts_tx_en = 1; | ||
1019 | break; | ||
1020 | default: | ||
1021 | return -ERANGE; | 1049 | return -ERANGE; |
1022 | } | 1050 | |
1051 | dp83640->hwts_tx_en = cfg.tx_type; | ||
1023 | 1052 | ||
1024 | switch (cfg.rx_filter) { | 1053 | switch (cfg.rx_filter) { |
1025 | case HWTSTAMP_FILTER_NONE: | 1054 | case HWTSTAMP_FILTER_NONE: |
@@ -1074,6 +1103,9 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) | |||
1074 | if (dp83640->hwts_tx_en) | 1103 | if (dp83640->hwts_tx_en) |
1075 | txcfg0 |= TX_TS_EN; | 1104 | txcfg0 |= TX_TS_EN; |
1076 | 1105 | ||
1106 | if (dp83640->hwts_tx_en == HWTSTAMP_TX_ONESTEP_SYNC) | ||
1107 | txcfg0 |= SYNC_1STEP | CHK_1STEP; | ||
1108 | |||
1077 | if (dp83640->hwts_rx_en) | 1109 | if (dp83640->hwts_rx_en) |
1078 | rxcfg0 |= RX_TS_EN; | 1110 | rxcfg0 |= RX_TS_EN; |
1079 | 1111 | ||
@@ -1156,12 +1188,24 @@ static void dp83640_txtstamp(struct phy_device *phydev, | |||
1156 | { | 1188 | { |
1157 | struct dp83640_private *dp83640 = phydev->priv; | 1189 | struct dp83640_private *dp83640 = phydev->priv; |
1158 | 1190 | ||
1159 | if (!dp83640->hwts_tx_en) { | 1191 | switch (dp83640->hwts_tx_en) { |
1192 | |||
1193 | case HWTSTAMP_TX_ONESTEP_SYNC: | ||
1194 | if (is_sync(skb, type)) { | ||
1195 | kfree_skb(skb); | ||
1196 | return; | ||
1197 | } | ||
1198 | /* fall through */ | ||
1199 | case HWTSTAMP_TX_ON: | ||
1200 | skb_queue_tail(&dp83640->tx_queue, skb); | ||
1201 | schedule_work(&dp83640->ts_work); | ||
1202 | break; | ||
1203 | |||
1204 | case HWTSTAMP_TX_OFF: | ||
1205 | default: | ||
1160 | kfree_skb(skb); | 1206 | kfree_skb(skb); |
1161 | return; | 1207 | break; |
1162 | } | 1208 | } |
1163 | skb_queue_tail(&dp83640->tx_queue, skb); | ||
1164 | schedule_work(&dp83640->ts_work); | ||
1165 | } | 1209 | } |
1166 | 1210 | ||
1167 | static struct phy_driver dp83640_driver = { | 1211 | static struct phy_driver dp83640_driver = { |