aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-02-14 14:33:38 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-14 14:33:38 -0500
commit64da58528bdbdba171cf6c6ffaf39c2ee75e3a10 (patch)
treed779fcb16a984e9c1070269050d885c2d73ce120
parente0f9759f530bf789e984961dce79f525b151ecf3 (diff)
parenta2e47134e577713add97124afd812bc3f93627fb (diff)
Merge branch 'PTP-support-for-DSA-and-mv88e6xxx-driver'
Andrew Lunn says: ==================== PTP support for DSA and mv88e6xxx driver. This patchset adds support for using the PTP hardware in switches supported by the mv88e6xxx driver. The code was produces in collaboration with Brandon Streiff doing the initial implementation, and then Richard Cochran and Andrew Lunn making further changes and cleanups. The code is sufficient to use ptp4l on a single DSA interface, either as a master or a slave. Due to the use of an MDIO bus to access the switch, reading hardware timestamps is slower than what ptp4l expects. Thus it is necessary to use the option --tx_timestamp_timeout=32. Heavy use of ethtool -S, or bridge fdb show can also upset ptp4l. Patches to address this will follow. Further work is requires to support bridges using Boundary Clock or Transparent Clock mode. Since the RFC, an overflow bug has been fixed. Brandon Streiff has also Acked-by: the updates to his initial patchset. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/mv88e6xxx/Kconfig10
-rw-r--r--drivers/net/dsa/mv88e6xxx/Makefile4
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c67
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h103
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.c9
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.h85
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2_avb.c193
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2_scratch.c240
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.c584
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.h172
-rw-r--r--drivers/net/dsa/mv88e6xxx/ptp.c381
-rw-r--r--drivers/net/dsa/mv88e6xxx/ptp.h108
-rw-r--r--include/linux/ptp_classify.h4
-rw-r--r--include/net/dsa.h20
-rw-r--r--net/dsa/dsa.c36
-rw-r--r--net/dsa/slave.c59
16 files changed, 2070 insertions, 5 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig
index 1aaa7a95ebc4..ae9e7f7cb31c 100644
--- a/drivers/net/dsa/mv88e6xxx/Kconfig
+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
@@ -18,3 +18,13 @@ config NET_DSA_MV88E6XXX_GLOBAL2
18 18
19 It is required on most chips. If the chip you compile the support for 19 It is required on most chips. If the chip you compile the support for
20 doesn't have such registers set, say N here. In doubt, say Y. 20 doesn't have such registers set, say N here. In doubt, say Y.
21
22config NET_DSA_MV88E6XXX_PTP
23 bool "PTP support for Marvell 88E6xxx"
24 default n
25 depends on NET_DSA_MV88E6XXX_GLOBAL2
26 imply NETWORK_PHY_TIMESTAMPING
27 imply PTP_1588_CLOCK
28 help
29 Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
30 chips that support it.
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 58a4a0014e59..50de304abe2f 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -5,6 +5,10 @@ mv88e6xxx-objs += global1.o
5mv88e6xxx-objs += global1_atu.o 5mv88e6xxx-objs += global1_atu.o
6mv88e6xxx-objs += global1_vtu.o 6mv88e6xxx-objs += global1_vtu.o
7mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o 7mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
8mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_avb.o
9mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o
10mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
8mv88e6xxx-objs += phy.o 11mv88e6xxx-objs += phy.o
9mv88e6xxx-objs += port.o 12mv88e6xxx-objs += port.o
13mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
10mv88e6xxx-objs += serdes.o 14mv88e6xxx-objs += serdes.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index eb328bade225..af63710e93c1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -36,8 +36,10 @@
36#include "chip.h" 36#include "chip.h"
37#include "global1.h" 37#include "global1.h"
38#include "global2.h" 38#include "global2.h"
39#include "hwtstamp.h"
39#include "phy.h" 40#include "phy.h"
40#include "port.h" 41#include "port.h"
42#include "ptp.h"
41#include "serdes.h" 43#include "serdes.h"
42 44
43static void assert_reg_lock(struct mv88e6xxx_chip *chip) 45static void assert_reg_lock(struct mv88e6xxx_chip *chip)
@@ -2092,6 +2094,17 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
2092 if (err) 2094 if (err)
2093 goto unlock; 2095 goto unlock;
2094 2096
2097 /* Setup PTP Hardware Clock and timestamping */
2098 if (chip->info->ptp_support) {
2099 err = mv88e6xxx_ptp_setup(chip);
2100 if (err)
2101 goto unlock;
2102
2103 err = mv88e6xxx_hwtstamp_setup(chip);
2104 if (err)
2105 goto unlock;
2106 }
2107
2095unlock: 2108unlock:
2096 mutex_unlock(&chip->reg_lock); 2109 mutex_unlock(&chip->reg_lock);
2097 2110
@@ -2472,6 +2485,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
2472 .reset = mv88e6352_g1_reset, 2485 .reset = mv88e6352_g1_reset,
2473 .vtu_getnext = mv88e6352_g1_vtu_getnext, 2486 .vtu_getnext = mv88e6352_g1_vtu_getnext,
2474 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2487 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2488 .gpio_ops = &mv88e6352_gpio_ops,
2475}; 2489};
2476 2490
2477static const struct mv88e6xxx_ops mv88e6161_ops = { 2491static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -2602,6 +2616,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
2602 .vtu_getnext = mv88e6352_g1_vtu_getnext, 2616 .vtu_getnext = mv88e6352_g1_vtu_getnext,
2603 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2617 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2604 .serdes_power = mv88e6352_serdes_power, 2618 .serdes_power = mv88e6352_serdes_power,
2619 .gpio_ops = &mv88e6352_gpio_ops,
2605}; 2620};
2606 2621
2607static const struct mv88e6xxx_ops mv88e6175_ops = { 2622static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -2673,6 +2688,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
2673 .vtu_getnext = mv88e6352_g1_vtu_getnext, 2688 .vtu_getnext = mv88e6352_g1_vtu_getnext,
2674 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2689 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2675 .serdes_power = mv88e6352_serdes_power, 2690 .serdes_power = mv88e6352_serdes_power,
2691 .gpio_ops = &mv88e6352_gpio_ops,
2676}; 2692};
2677 2693
2678static const struct mv88e6xxx_ops mv88e6185_ops = { 2694static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -2736,6 +2752,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
2736 .vtu_getnext = mv88e6390_g1_vtu_getnext, 2752 .vtu_getnext = mv88e6390_g1_vtu_getnext,
2737 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 2753 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2738 .serdes_power = mv88e6390_serdes_power, 2754 .serdes_power = mv88e6390_serdes_power,
2755 .gpio_ops = &mv88e6352_gpio_ops,
2739}; 2756};
2740 2757
2741static const struct mv88e6xxx_ops mv88e6190x_ops = { 2758static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -2771,6 +2788,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
2771 .vtu_getnext = mv88e6390_g1_vtu_getnext, 2788 .vtu_getnext = mv88e6390_g1_vtu_getnext,
2772 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 2789 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2773 .serdes_power = mv88e6390_serdes_power, 2790 .serdes_power = mv88e6390_serdes_power,
2791 .gpio_ops = &mv88e6352_gpio_ops,
2774}; 2792};
2775 2793
2776static const struct mv88e6xxx_ops mv88e6191_ops = { 2794static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -2843,6 +2861,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
2843 .vtu_getnext = mv88e6352_g1_vtu_getnext, 2861 .vtu_getnext = mv88e6352_g1_vtu_getnext,
2844 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2862 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2845 .serdes_power = mv88e6352_serdes_power, 2863 .serdes_power = mv88e6352_serdes_power,
2864 .gpio_ops = &mv88e6352_gpio_ops,
2865 .avb_ops = &mv88e6352_avb_ops,
2846}; 2866};
2847 2867
2848static const struct mv88e6xxx_ops mv88e6290_ops = { 2868static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -2879,6 +2899,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
2879 .vtu_getnext = mv88e6390_g1_vtu_getnext, 2899 .vtu_getnext = mv88e6390_g1_vtu_getnext,
2880 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 2900 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2881 .serdes_power = mv88e6390_serdes_power, 2901 .serdes_power = mv88e6390_serdes_power,
2902 .gpio_ops = &mv88e6352_gpio_ops,
2903 .avb_ops = &mv88e6390_avb_ops,
2882}; 2904};
2883 2905
2884static const struct mv88e6xxx_ops mv88e6320_ops = { 2906static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -2913,6 +2935,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
2913 .reset = mv88e6352_g1_reset, 2935 .reset = mv88e6352_g1_reset,
2914 .vtu_getnext = mv88e6185_g1_vtu_getnext, 2936 .vtu_getnext = mv88e6185_g1_vtu_getnext,
2915 .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2937 .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2938 .gpio_ops = &mv88e6352_gpio_ops,
2939 .avb_ops = &mv88e6352_avb_ops,
2916}; 2940};
2917 2941
2918static const struct mv88e6xxx_ops mv88e6321_ops = { 2942static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -2945,6 +2969,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
2945 .reset = mv88e6352_g1_reset, 2969 .reset = mv88e6352_g1_reset,
2946 .vtu_getnext = mv88e6185_g1_vtu_getnext, 2970 .vtu_getnext = mv88e6185_g1_vtu_getnext,
2947 .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 2971 .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2972 .gpio_ops = &mv88e6352_gpio_ops,
2973 .avb_ops = &mv88e6352_avb_ops,
2948}; 2974};
2949 2975
2950static const struct mv88e6xxx_ops mv88e6341_ops = { 2976static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -2981,6 +3007,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
2981 .reset = mv88e6352_g1_reset, 3007 .reset = mv88e6352_g1_reset,
2982 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3008 .vtu_getnext = mv88e6352_g1_vtu_getnext,
2983 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3009 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3010 .gpio_ops = &mv88e6352_gpio_ops,
3011 .avb_ops = &mv88e6390_avb_ops,
2984}; 3012};
2985 3013
2986static const struct mv88e6xxx_ops mv88e6350_ops = { 3014static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3049,6 +3077,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
3049 .reset = mv88e6352_g1_reset, 3077 .reset = mv88e6352_g1_reset,
3050 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3078 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3051 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3079 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3080 .avb_ops = &mv88e6352_avb_ops,
3052}; 3081};
3053 3082
3054static const struct mv88e6xxx_ops mv88e6352_ops = { 3083static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3086,6 +3115,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
3086 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3115 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3087 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3116 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3088 .serdes_power = mv88e6352_serdes_power, 3117 .serdes_power = mv88e6352_serdes_power,
3118 .gpio_ops = &mv88e6352_gpio_ops,
3119 .avb_ops = &mv88e6352_avb_ops,
3089}; 3120};
3090 3121
3091static const struct mv88e6xxx_ops mv88e6390_ops = { 3122static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3124,6 +3155,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
3124 .vtu_getnext = mv88e6390_g1_vtu_getnext, 3155 .vtu_getnext = mv88e6390_g1_vtu_getnext,
3125 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3156 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3126 .serdes_power = mv88e6390_serdes_power, 3157 .serdes_power = mv88e6390_serdes_power,
3158 .gpio_ops = &mv88e6352_gpio_ops,
3159 .avb_ops = &mv88e6390_avb_ops,
3127}; 3160};
3128 3161
3129static const struct mv88e6xxx_ops mv88e6390x_ops = { 3162static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3162,6 +3195,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
3162 .vtu_getnext = mv88e6390_g1_vtu_getnext, 3195 .vtu_getnext = mv88e6390_g1_vtu_getnext,
3163 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3196 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3164 .serdes_power = mv88e6390_serdes_power, 3197 .serdes_power = mv88e6390_serdes_power,
3198 .gpio_ops = &mv88e6352_gpio_ops,
3199 .avb_ops = &mv88e6390_avb_ops,
3165}; 3200};
3166 3201
3167static const struct mv88e6xxx_info mv88e6xxx_table[] = { 3202static const struct mv88e6xxx_info mv88e6xxx_table[] = {
@@ -3267,6 +3302,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3267 .name = "Marvell 88E6341", 3302 .name = "Marvell 88E6341",
3268 .num_databases = 4096, 3303 .num_databases = 4096,
3269 .num_ports = 6, 3304 .num_ports = 6,
3305 .num_gpio = 11,
3270 .max_vid = 4095, 3306 .max_vid = 4095,
3271 .port_base_addr = 0x10, 3307 .port_base_addr = 0x10,
3272 .global1_addr = 0x1b, 3308 .global1_addr = 0x1b,
@@ -3346,6 +3382,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3346 .name = "Marvell 88E6172", 3382 .name = "Marvell 88E6172",
3347 .num_databases = 4096, 3383 .num_databases = 4096,
3348 .num_ports = 7, 3384 .num_ports = 7,
3385 .num_gpio = 15,
3349 .max_vid = 4095, 3386 .max_vid = 4095,
3350 .port_base_addr = 0x10, 3387 .port_base_addr = 0x10,
3351 .global1_addr = 0x1b, 3388 .global1_addr = 0x1b,
@@ -3386,6 +3423,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3386 .name = "Marvell 88E6176", 3423 .name = "Marvell 88E6176",
3387 .num_databases = 4096, 3424 .num_databases = 4096,
3388 .num_ports = 7, 3425 .num_ports = 7,
3426 .num_gpio = 15,
3389 .max_vid = 4095, 3427 .max_vid = 4095,
3390 .port_base_addr = 0x10, 3428 .port_base_addr = 0x10,
3391 .global1_addr = 0x1b, 3429 .global1_addr = 0x1b,
@@ -3424,6 +3462,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3424 .name = "Marvell 88E6190", 3462 .name = "Marvell 88E6190",
3425 .num_databases = 4096, 3463 .num_databases = 4096,
3426 .num_ports = 11, /* 10 + Z80 */ 3464 .num_ports = 11, /* 10 + Z80 */
3465 .num_gpio = 16,
3427 .max_vid = 8191, 3466 .max_vid = 8191,
3428 .port_base_addr = 0x0, 3467 .port_base_addr = 0x0,
3429 .global1_addr = 0x1b, 3468 .global1_addr = 0x1b,
@@ -3444,6 +3483,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3444 .name = "Marvell 88E6190X", 3483 .name = "Marvell 88E6190X",
3445 .num_databases = 4096, 3484 .num_databases = 4096,
3446 .num_ports = 11, /* 10 + Z80 */ 3485 .num_ports = 11, /* 10 + Z80 */
3486 .num_gpio = 16,
3447 .max_vid = 8191, 3487 .max_vid = 8191,
3448 .port_base_addr = 0x0, 3488 .port_base_addr = 0x0,
3449 .global1_addr = 0x1b, 3489 .global1_addr = 0x1b,
@@ -3475,6 +3515,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3475 .pvt = true, 3515 .pvt = true,
3476 .multi_chip = true, 3516 .multi_chip = true,
3477 .tag_protocol = DSA_TAG_PROTO_DSA, 3517 .tag_protocol = DSA_TAG_PROTO_DSA,
3518 .ptp_support = true,
3478 .ops = &mv88e6191_ops, 3519 .ops = &mv88e6191_ops,
3479 }, 3520 },
3480 3521
@@ -3484,6 +3525,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3484 .name = "Marvell 88E6240", 3525 .name = "Marvell 88E6240",
3485 .num_databases = 4096, 3526 .num_databases = 4096,
3486 .num_ports = 7, 3527 .num_ports = 7,
3528 .num_gpio = 15,
3487 .max_vid = 4095, 3529 .max_vid = 4095,
3488 .port_base_addr = 0x10, 3530 .port_base_addr = 0x10,
3489 .global1_addr = 0x1b, 3531 .global1_addr = 0x1b,
@@ -3495,6 +3537,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3495 .pvt = true, 3537 .pvt = true,
3496 .multi_chip = true, 3538 .multi_chip = true,
3497 .tag_protocol = DSA_TAG_PROTO_EDSA, 3539 .tag_protocol = DSA_TAG_PROTO_EDSA,
3540 .ptp_support = true,
3498 .ops = &mv88e6240_ops, 3541 .ops = &mv88e6240_ops,
3499 }, 3542 },
3500 3543
@@ -3504,6 +3547,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3504 .name = "Marvell 88E6290", 3547 .name = "Marvell 88E6290",
3505 .num_databases = 4096, 3548 .num_databases = 4096,
3506 .num_ports = 11, /* 10 + Z80 */ 3549 .num_ports = 11, /* 10 + Z80 */
3550 .num_gpio = 16,
3507 .max_vid = 8191, 3551 .max_vid = 8191,
3508 .port_base_addr = 0x0, 3552 .port_base_addr = 0x0,
3509 .global1_addr = 0x1b, 3553 .global1_addr = 0x1b,
@@ -3515,6 +3559,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3515 .pvt = true, 3559 .pvt = true,
3516 .multi_chip = true, 3560 .multi_chip = true,
3517 .tag_protocol = DSA_TAG_PROTO_DSA, 3561 .tag_protocol = DSA_TAG_PROTO_DSA,
3562 .ptp_support = true,
3518 .ops = &mv88e6290_ops, 3563 .ops = &mv88e6290_ops,
3519 }, 3564 },
3520 3565
@@ -3524,6 +3569,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3524 .name = "Marvell 88E6320", 3569 .name = "Marvell 88E6320",
3525 .num_databases = 4096, 3570 .num_databases = 4096,
3526 .num_ports = 7, 3571 .num_ports = 7,
3572 .num_gpio = 15,
3527 .max_vid = 4095, 3573 .max_vid = 4095,
3528 .port_base_addr = 0x10, 3574 .port_base_addr = 0x10,
3529 .global1_addr = 0x1b, 3575 .global1_addr = 0x1b,
@@ -3534,6 +3580,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3534 .pvt = true, 3580 .pvt = true,
3535 .multi_chip = true, 3581 .multi_chip = true,
3536 .tag_protocol = DSA_TAG_PROTO_EDSA, 3582 .tag_protocol = DSA_TAG_PROTO_EDSA,
3583 .ptp_support = true,
3537 .ops = &mv88e6320_ops, 3584 .ops = &mv88e6320_ops,
3538 }, 3585 },
3539 3586
@@ -3543,6 +3590,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3543 .name = "Marvell 88E6321", 3590 .name = "Marvell 88E6321",
3544 .num_databases = 4096, 3591 .num_databases = 4096,
3545 .num_ports = 7, 3592 .num_ports = 7,
3593 .num_gpio = 15,
3546 .max_vid = 4095, 3594 .max_vid = 4095,
3547 .port_base_addr = 0x10, 3595 .port_base_addr = 0x10,
3548 .global1_addr = 0x1b, 3596 .global1_addr = 0x1b,
@@ -3552,6 +3600,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3552 .atu_move_port_mask = 0xf, 3600 .atu_move_port_mask = 0xf,
3553 .multi_chip = true, 3601 .multi_chip = true,
3554 .tag_protocol = DSA_TAG_PROTO_EDSA, 3602 .tag_protocol = DSA_TAG_PROTO_EDSA,
3603 .ptp_support = true,
3555 .ops = &mv88e6321_ops, 3604 .ops = &mv88e6321_ops,
3556 }, 3605 },
3557 3606
@@ -3561,6 +3610,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3561 .name = "Marvell 88E6341", 3610 .name = "Marvell 88E6341",
3562 .num_databases = 4096, 3611 .num_databases = 4096,
3563 .num_ports = 6, 3612 .num_ports = 6,
3613 .num_gpio = 11,
3564 .max_vid = 4095, 3614 .max_vid = 4095,
3565 .port_base_addr = 0x10, 3615 .port_base_addr = 0x10,
3566 .global1_addr = 0x1b, 3616 .global1_addr = 0x1b,
@@ -3571,6 +3621,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3571 .pvt = true, 3621 .pvt = true,
3572 .multi_chip = true, 3622 .multi_chip = true,
3573 .tag_protocol = DSA_TAG_PROTO_EDSA, 3623 .tag_protocol = DSA_TAG_PROTO_EDSA,
3624 .ptp_support = true,
3574 .ops = &mv88e6341_ops, 3625 .ops = &mv88e6341_ops,
3575 }, 3626 },
3576 3627
@@ -3620,6 +3671,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3620 .name = "Marvell 88E6352", 3671 .name = "Marvell 88E6352",
3621 .num_databases = 4096, 3672 .num_databases = 4096,
3622 .num_ports = 7, 3673 .num_ports = 7,
3674 .num_gpio = 15,
3623 .max_vid = 4095, 3675 .max_vid = 4095,
3624 .port_base_addr = 0x10, 3676 .port_base_addr = 0x10,
3625 .global1_addr = 0x1b, 3677 .global1_addr = 0x1b,
@@ -3631,6 +3683,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3631 .pvt = true, 3683 .pvt = true,
3632 .multi_chip = true, 3684 .multi_chip = true,
3633 .tag_protocol = DSA_TAG_PROTO_EDSA, 3685 .tag_protocol = DSA_TAG_PROTO_EDSA,
3686 .ptp_support = true,
3634 .ops = &mv88e6352_ops, 3687 .ops = &mv88e6352_ops,
3635 }, 3688 },
3636 [MV88E6390] = { 3689 [MV88E6390] = {
@@ -3639,6 +3692,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3639 .name = "Marvell 88E6390", 3692 .name = "Marvell 88E6390",
3640 .num_databases = 4096, 3693 .num_databases = 4096,
3641 .num_ports = 11, /* 10 + Z80 */ 3694 .num_ports = 11, /* 10 + Z80 */
3695 .num_gpio = 16,
3642 .max_vid = 8191, 3696 .max_vid = 8191,
3643 .port_base_addr = 0x0, 3697 .port_base_addr = 0x0,
3644 .global1_addr = 0x1b, 3698 .global1_addr = 0x1b,
@@ -3650,6 +3704,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3650 .pvt = true, 3704 .pvt = true,
3651 .multi_chip = true, 3705 .multi_chip = true,
3652 .tag_protocol = DSA_TAG_PROTO_DSA, 3706 .tag_protocol = DSA_TAG_PROTO_DSA,
3707 .ptp_support = true,
3653 .ops = &mv88e6390_ops, 3708 .ops = &mv88e6390_ops,
3654 }, 3709 },
3655 [MV88E6390X] = { 3710 [MV88E6390X] = {
@@ -3658,6 +3713,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3658 .name = "Marvell 88E6390X", 3713 .name = "Marvell 88E6390X",
3659 .num_databases = 4096, 3714 .num_databases = 4096,
3660 .num_ports = 11, /* 10 + Z80 */ 3715 .num_ports = 11, /* 10 + Z80 */
3716 .num_gpio = 16,
3661 .max_vid = 8191, 3717 .max_vid = 8191,
3662 .port_base_addr = 0x0, 3718 .port_base_addr = 0x0,
3663 .global1_addr = 0x1b, 3719 .global1_addr = 0x1b,
@@ -3669,6 +3725,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3669 .pvt = true, 3725 .pvt = true,
3670 .multi_chip = true, 3726 .multi_chip = true,
3671 .tag_protocol = DSA_TAG_PROTO_DSA, 3727 .tag_protocol = DSA_TAG_PROTO_DSA,
3728 .ptp_support = true,
3672 .ops = &mv88e6390x_ops, 3729 .ops = &mv88e6390x_ops,
3673 }, 3730 },
3674}; 3731};
@@ -3880,6 +3937,11 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
3880 .port_mdb_del = mv88e6xxx_port_mdb_del, 3937 .port_mdb_del = mv88e6xxx_port_mdb_del,
3881 .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 3938 .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join,
3882 .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 3939 .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave,
3940 .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set,
3941 .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get,
3942 .port_txtstamp = mv88e6xxx_port_txtstamp,
3943 .port_rxtstamp = mv88e6xxx_port_rxtstamp,
3944 .get_ts_info = mv88e6xxx_get_ts_info,
3883}; 3945};
3884 3946
3885static struct dsa_switch_driver mv88e6xxx_switch_drv = { 3947static struct dsa_switch_driver mv88e6xxx_switch_drv = {
@@ -4022,6 +4084,11 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4022 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 4084 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
4023 struct mv88e6xxx_chip *chip = ds->priv; 4085 struct mv88e6xxx_chip *chip = ds->priv;
4024 4086
4087 if (chip->info->ptp_support) {
4088 mv88e6xxx_hwtstamp_free(chip);
4089 mv88e6xxx_ptp_free(chip);
4090 }
4091
4025 mv88e6xxx_phy_destroy(chip); 4092 mv88e6xxx_phy_destroy(chip);
4026 mv88e6xxx_unregister_switch(chip); 4093 mv88e6xxx_unregister_switch(chip);
4027 mv88e6xxx_mdios_unregister(chip); 4094 mv88e6xxx_mdios_unregister(chip);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 3dba6e90adcf..97d7915f32c7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -16,6 +16,8 @@
16#include <linux/irq.h> 16#include <linux/irq.h>
17#include <linux/gpio/consumer.h> 17#include <linux/gpio/consumer.h>
18#include <linux/phy.h> 18#include <linux/phy.h>
19#include <linux/ptp_clock_kernel.h>
20#include <linux/timecounter.h>
19#include <net/dsa.h> 21#include <net/dsa.h>
20 22
21#ifndef UINT64_MAX 23#ifndef UINT64_MAX
@@ -39,6 +41,8 @@
39#define MV88E6XXX_MAX_PVT_SWITCHES 32 41#define MV88E6XXX_MAX_PVT_SWITCHES 32
40#define MV88E6XXX_MAX_PVT_PORTS 16 42#define MV88E6XXX_MAX_PVT_PORTS 16
41 43
44#define MV88E6XXX_MAX_GPIO 16
45
42enum mv88e6xxx_egress_mode { 46enum mv88e6xxx_egress_mode {
43 MV88E6XXX_EGRESS_MODE_UNMODIFIED, 47 MV88E6XXX_EGRESS_MODE_UNMODIFIED,
44 MV88E6XXX_EGRESS_MODE_UNTAGGED, 48 MV88E6XXX_EGRESS_MODE_UNTAGGED,
@@ -105,6 +109,7 @@ struct mv88e6xxx_info {
105 const char *name; 109 const char *name;
106 unsigned int num_databases; 110 unsigned int num_databases;
107 unsigned int num_ports; 111 unsigned int num_ports;
112 unsigned int num_gpio;
108 unsigned int max_vid; 113 unsigned int max_vid;
109 unsigned int port_base_addr; 114 unsigned int port_base_addr;
110 unsigned int global1_addr; 115 unsigned int global1_addr;
@@ -126,6 +131,9 @@ struct mv88e6xxx_info {
126 */ 131 */
127 u8 atu_move_port_mask; 132 u8 atu_move_port_mask;
128 const struct mv88e6xxx_ops *ops; 133 const struct mv88e6xxx_ops *ops;
134
135 /* Supports PTP */
136 bool ptp_support;
129}; 137};
130 138
131struct mv88e6xxx_atu_entry { 139struct mv88e6xxx_atu_entry {
@@ -146,6 +154,8 @@ struct mv88e6xxx_vtu_entry {
146 154
147struct mv88e6xxx_bus_ops; 155struct mv88e6xxx_bus_ops;
148struct mv88e6xxx_irq_ops; 156struct mv88e6xxx_irq_ops;
157struct mv88e6xxx_gpio_ops;
158struct mv88e6xxx_avb_ops;
149 159
150struct mv88e6xxx_irq { 160struct mv88e6xxx_irq {
151 u16 masked; 161 u16 masked;
@@ -154,6 +164,32 @@ struct mv88e6xxx_irq {
154 unsigned int nirqs; 164 unsigned int nirqs;
155}; 165};
156 166
167/* state flags for mv88e6xxx_port_hwtstamp::state */
168enum {
169 MV88E6XXX_HWTSTAMP_ENABLED,
170 MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
171};
172
173struct mv88e6xxx_port_hwtstamp {
174 /* Port index */
175 int port_id;
176
177 /* Timestamping state */
178 unsigned long state;
179
180 /* Resources for receive timestamping */
181 struct sk_buff_head rx_queue;
182 struct sk_buff_head rx_queue2;
183
184 /* Resources for transmit timestamping */
185 unsigned long tx_tstamp_start;
186 struct sk_buff *tx_skb;
187 u16 tx_seq_id;
188
189 /* Current timestamp configuration */
190 struct hwtstamp_config tstamp_config;
191};
192
157struct mv88e6xxx_chip { 193struct mv88e6xxx_chip {
158 const struct mv88e6xxx_info *info; 194 const struct mv88e6xxx_info *info;
159 195
@@ -209,6 +245,26 @@ struct mv88e6xxx_chip {
209 int watchdog_irq; 245 int watchdog_irq;
210 int atu_prob_irq; 246 int atu_prob_irq;
211 int vtu_prob_irq; 247 int vtu_prob_irq;
248
249 /* GPIO resources */
250 u8 gpio_data[2];
251
252 /* This cyclecounter abstracts the switch PTP time.
253 * reg_lock must be held for any operation that read()s.
254 */
255 struct cyclecounter tstamp_cc;
256 struct timecounter tstamp_tc;
257 struct delayed_work overflow_work;
258
259 struct ptp_clock *ptp_clock;
260 struct ptp_clock_info ptp_clock_info;
261 struct delayed_work tai_event_work;
262 struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO];
263 u16 trig_config;
264 u16 evcap_config;
265
266 /* Per-port timestamping resources. */
267 struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
212}; 268};
213 269
214struct mv88e6xxx_bus_ops { 270struct mv88e6xxx_bus_ops {
@@ -344,6 +400,12 @@ struct mv88e6xxx_ops {
344 struct mv88e6xxx_vtu_entry *entry); 400 struct mv88e6xxx_vtu_entry *entry);
345 int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, 401 int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip,
346 struct mv88e6xxx_vtu_entry *entry); 402 struct mv88e6xxx_vtu_entry *entry);
403
404 /* GPIO operations */
405 const struct mv88e6xxx_gpio_ops *gpio_ops;
406
407 /* Interface to the AVB/PTP registers */
408 const struct mv88e6xxx_avb_ops *avb_ops;
347}; 409};
348 410
349struct mv88e6xxx_irq_ops { 411struct mv88e6xxx_irq_ops {
@@ -355,6 +417,42 @@ struct mv88e6xxx_irq_ops {
355 void (*irq_free)(struct mv88e6xxx_chip *chip); 417 void (*irq_free)(struct mv88e6xxx_chip *chip);
356}; 418};
357 419
420struct mv88e6xxx_gpio_ops {
421 /* Get/set data on GPIO pin */
422 int (*get_data)(struct mv88e6xxx_chip *chip, unsigned int pin);
423 int (*set_data)(struct mv88e6xxx_chip *chip, unsigned int pin,
424 int value);
425
426 /* get/set GPIO direction */
427 int (*get_dir)(struct mv88e6xxx_chip *chip, unsigned int pin);
428 int (*set_dir)(struct mv88e6xxx_chip *chip, unsigned int pin,
429 bool input);
430
431 /* get/set GPIO pin control */
432 int (*get_pctl)(struct mv88e6xxx_chip *chip, unsigned int pin,
433 int *func);
434 int (*set_pctl)(struct mv88e6xxx_chip *chip, unsigned int pin,
435 int func);
436};
437
438struct mv88e6xxx_avb_ops {
439 /* Access port-scoped Precision Time Protocol registers */
440 int (*port_ptp_read)(struct mv88e6xxx_chip *chip, int port, int addr,
441 u16 *data, int len);
442 int (*port_ptp_write)(struct mv88e6xxx_chip *chip, int port, int addr,
443 u16 data);
444
445 /* Access global Precision Time Protocol registers */
446 int (*ptp_read)(struct mv88e6xxx_chip *chip, int addr, u16 *data,
447 int len);
448 int (*ptp_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
449
450 /* Access global Time Application Interface registers */
451 int (*tai_read)(struct mv88e6xxx_chip *chip, int addr, u16 *data,
452 int len);
453 int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
454};
455
358#define STATS_TYPE_PORT BIT(0) 456#define STATS_TYPE_PORT BIT(0)
359#define STATS_TYPE_BANK0 BIT(1) 457#define STATS_TYPE_BANK0 BIT(1)
360#define STATS_TYPE_BANK1 BIT(2) 458#define STATS_TYPE_BANK1 BIT(2)
@@ -386,6 +484,11 @@ static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip)
386 return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); 484 return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
387} 485}
388 486
487static inline unsigned int mv88e6xxx_num_gpio(struct mv88e6xxx_chip *chip)
488{
489 return chip->info->num_gpio;
490}
491
389int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); 492int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
390int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); 493int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
391int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, 494int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c
index af0727877825..5f370f1fc7c4 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -20,22 +20,22 @@
20#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */ 20#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
21#include "global2.h" 21#include "global2.h"
22 22
23static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) 23int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
24{ 24{
25 return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val); 25 return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
26} 26}
27 27
28static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val) 28int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
29{ 29{
30 return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val); 30 return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
31} 31}
32 32
33static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update) 33int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
34{ 34{
35 return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update); 35 return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update);
36} 36}
37 37
38static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) 38int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
39{ 39{
40 return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask); 40 return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
41} 41}
@@ -798,6 +798,7 @@ int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
798 val); 798 val);
799} 799}
800 800
801/* Offset 0x1B: Watchdog Control */
801static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq) 802static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
802{ 803{
803 u16 reg; 804 u16 reg;
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 669f59017b12..25f92b3d7157 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -149,7 +149,26 @@
149#define MV88E6390_G2_EEPROM_ADDR_MASK 0xffff 149#define MV88E6390_G2_EEPROM_ADDR_MASK 0xffff
150 150
151/* Offset 0x16: AVB Command Register */ 151/* Offset 0x16: AVB Command Register */
152#define MV88E6352_G2_AVB_CMD 0x16 152#define MV88E6352_G2_AVB_CMD 0x16
153#define MV88E6352_G2_AVB_CMD_BUSY 0x8000
154#define MV88E6352_G2_AVB_CMD_OP_READ 0x4000
155#define MV88E6352_G2_AVB_CMD_OP_READ_INCR 0x6000
156#define MV88E6352_G2_AVB_CMD_OP_WRITE 0x3000
157#define MV88E6390_G2_AVB_CMD_OP_READ 0x0000
158#define MV88E6390_G2_AVB_CMD_OP_READ_INCR 0x4000
159#define MV88E6390_G2_AVB_CMD_OP_WRITE 0x6000
160#define MV88E6352_G2_AVB_CMD_PORT_MASK 0x0f00
161#define MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL 0xe
162#define MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL 0xf
163#define MV88E6390_G2_AVB_CMD_PORT_MASK 0x1f00
164#define MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL 0x1e
165#define MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL 0x1f
166#define MV88E6352_G2_AVB_CMD_BLOCK_PTP 0
167#define MV88E6352_G2_AVB_CMD_BLOCK_AVB 1
168#define MV88E6352_G2_AVB_CMD_BLOCK_QAV 2
169#define MV88E6352_G2_AVB_CMD_BLOCK_QVB 3
170#define MV88E6352_G2_AVB_CMD_BLOCK_MASK 0x00e0
171#define MV88E6352_G2_AVB_CMD_ADDR_MASK 0x001f
153 172
154/* Offset 0x17: AVB Data Register */ 173/* Offset 0x17: AVB Data Register */
155#define MV88E6352_G2_AVB_DATA 0x17 174#define MV88E6352_G2_AVB_DATA 0x17
@@ -223,6 +242,35 @@
223#define MV88E6352_G2_NOEGR_POLICY 0x2000 242#define MV88E6352_G2_NOEGR_POLICY 0x2000
224#define MV88E6390_G2_LAG_ID_4 0x2000 243#define MV88E6390_G2_LAG_ID_4 0x2000
225 244
245/* Scratch/Misc registers accessed through MV88E6XXX_G2_SCRATCH_MISC */
246/* Offset 0x02: Misc Configuration */
247#define MV88E6352_G2_SCRATCH_MISC_CFG 0x02
248#define MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI 0x80
249/* Offset 0x60-0x61: GPIO Configuration */
250#define MV88E6352_G2_SCRATCH_GPIO_CFG0 0x60
251#define MV88E6352_G2_SCRATCH_GPIO_CFG1 0x61
252/* Offset 0x62-0x63: GPIO Direction */
253#define MV88E6352_G2_SCRATCH_GPIO_DIR0 0x62
254#define MV88E6352_G2_SCRATCH_GPIO_DIR1 0x63
255#define MV88E6352_G2_SCRATCH_GPIO_DIR_OUT 0
256#define MV88E6352_G2_SCRATCH_GPIO_DIR_IN 1
257/* Offset 0x64-0x65: GPIO Data */
258#define MV88E6352_G2_SCRATCH_GPIO_DATA0 0x64
259#define MV88E6352_G2_SCRATCH_GPIO_DATA1 0x65
260/* Offset 0x68-0x6F: GPIO Pin Control */
261#define MV88E6352_G2_SCRATCH_GPIO_PCTL0 0x68
262#define MV88E6352_G2_SCRATCH_GPIO_PCTL1 0x69
263#define MV88E6352_G2_SCRATCH_GPIO_PCTL2 0x6A
264#define MV88E6352_G2_SCRATCH_GPIO_PCTL3 0x6B
265#define MV88E6352_G2_SCRATCH_GPIO_PCTL4 0x6C
266#define MV88E6352_G2_SCRATCH_GPIO_PCTL5 0x6D
267#define MV88E6352_G2_SCRATCH_GPIO_PCTL6 0x6E
268#define MV88E6352_G2_SCRATCH_GPIO_PCTL7 0x6F
269
270#define MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO 0
271#define MV88E6352_G2_SCRATCH_GPIO_PCTL_TRIG 1
272#define MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ 2
273
226#ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 274#ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2
227 275
228static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip) 276static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
@@ -230,6 +278,11 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
230 return 0; 278 return 0;
231} 279}
232 280
281int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
282int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
283int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update);
284int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
285
233int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port); 286int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
234int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port); 287int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
235 288
@@ -267,6 +320,11 @@ int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip);
267extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops; 320extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
268extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops; 321extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
269 322
323extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops;
324extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops;
325
326extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops;
327
270#else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */ 328#else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
271 329
272static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip) 330static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
@@ -279,6 +337,26 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
279 return 0; 337 return 0;
280} 338}
281 339
340static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
341{
342 return -EOPNOTSUPP;
343}
344
345static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
346{
347 return -EOPNOTSUPP;
348}
349
350static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
351{
352 return -EOPNOTSUPP;
353}
354
355static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
356{
357 return -EOPNOTSUPP;
358}
359
282static inline int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, 360static inline int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip,
283 int port) 361 int port)
284{ 362{
@@ -382,6 +460,11 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
382static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {}; 460static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
383static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {}; 461static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
384 462
463static const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {};
464static const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {};
465
466static const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {};
467
385#endif /* CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */ 468#endif /* CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
386 469
387#endif /* _MV88E6XXX_GLOBAL2_H */ 470#endif /* _MV88E6XXX_GLOBAL2_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global2_avb.c b/drivers/net/dsa/mv88e6xxx/global2_avb.c
new file mode 100644
index 000000000000..2e398ccb88ca
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/global2_avb.c
@@ -0,0 +1,193 @@
1/*
2 * Marvell 88E6xxx Switch Global 2 Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
7 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
8 *
9 * Copyright (c) 2017 National Instruments
10 * Brandon Streiff <brandon.streiff@ni.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18#include "global2.h"
19
20/* Offset 0x16: AVB Command Register
21 * Offset 0x17: AVB Data Register
22 *
23 * There are two different versions of this register interface:
24 * "6352": 3-bit "op" field, 4-bit "port" field.
25 * "6390": 2-bit "op" field, 5-bit "port" field.
26 *
27 * The "op" codes are different between the two, as well as the special
28 * port fields for global PTP and TAI configuration.
29 */
30
31/* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
32 * The hardware supports snapshotting up to four contiguous registers.
33 */
34static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
35 u16 *data, int len)
36{
37 int err;
38 int i;
39
40 /* Hardware can only snapshot four words. */
41 if (len > 4)
42 return -E2BIG;
43
44 err = mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, readop);
45 if (err)
46 return err;
47
48 for (i = 0; i < len; ++i) {
49 err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
50 &data[i]);
51 if (err)
52 return err;
53 }
54
55 return 0;
56}
57
58/* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
59static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
60 u16 data)
61{
62 int err;
63
64 err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
65 if (err)
66 return err;
67
68 return mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, writeop);
69}
70
71static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
72 int port, int addr, u16 *data,
73 int len)
74{
75 u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
76 MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
77 (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
78 addr;
79
80 return mv88e6xxx_g2_avb_read(chip, readop, data, len);
81}
82
83static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
84 int port, int addr, u16 data)
85{
86 u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
87 (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
88
89 return mv88e6xxx_g2_avb_write(chip, writeop, data);
90}
91
92static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
93 u16 *data, int len)
94{
95 return mv88e6352_g2_avb_port_ptp_read(chip,
96 MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
97 addr, data, len);
98}
99
100static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
101 u16 data)
102{
103 return mv88e6352_g2_avb_port_ptp_write(chip,
104 MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
105 addr, data);
106}
107
108static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
109 u16 *data, int len)
110{
111 return mv88e6352_g2_avb_port_ptp_read(chip,
112 MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
113 addr, data, len);
114}
115
116static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
117 u16 data)
118{
119 return mv88e6352_g2_avb_port_ptp_write(chip,
120 MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
121 addr, data);
122}
123
124const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
125 .port_ptp_read = mv88e6352_g2_avb_port_ptp_read,
126 .port_ptp_write = mv88e6352_g2_avb_port_ptp_write,
127 .ptp_read = mv88e6352_g2_avb_ptp_read,
128 .ptp_write = mv88e6352_g2_avb_ptp_write,
129 .tai_read = mv88e6352_g2_avb_tai_read,
130 .tai_write = mv88e6352_g2_avb_tai_write,
131};
132
133static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
134 int port, int addr, u16 *data,
135 int len)
136{
137 u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
138 MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
139 (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
140 addr;
141
142 return mv88e6xxx_g2_avb_read(chip, readop, data, len);
143}
144
145static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
146 int port, int addr, u16 data)
147{
148 u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
149 (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
150
151 return mv88e6xxx_g2_avb_write(chip, writeop, data);
152}
153
154static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
155 u16 *data, int len)
156{
157 return mv88e6390_g2_avb_port_ptp_read(chip,
158 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
159 addr, data, len);
160}
161
162static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
163 u16 data)
164{
165 return mv88e6390_g2_avb_port_ptp_write(chip,
166 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
167 addr, data);
168}
169
170static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
171 u16 *data, int len)
172{
173 return mv88e6390_g2_avb_port_ptp_read(chip,
174 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
175 addr, data, len);
176}
177
178static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
179 u16 data)
180{
181 return mv88e6390_g2_avb_port_ptp_write(chip,
182 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
183 addr, data);
184}
185
186const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
187 .port_ptp_read = mv88e6390_g2_avb_port_ptp_read,
188 .port_ptp_write = mv88e6390_g2_avb_port_ptp_write,
189 .ptp_read = mv88e6390_g2_avb_ptp_read,
190 .ptp_write = mv88e6390_g2_avb_ptp_write,
191 .tai_read = mv88e6390_g2_avb_tai_read,
192 .tai_write = mv88e6390_g2_avb_tai_write,
193};
diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
new file mode 100644
index 000000000000..0ff12bff9f0e
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
@@ -0,0 +1,240 @@
1/*
2 * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Brandon Streiff <brandon.streiff@ni.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#include "chip.h"
16#include "global2.h"
17
18/* Offset 0x1A: Scratch and Misc. Register */
19static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
20 u8 *data)
21{
22 u16 value;
23 int err;
24
25 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
26 reg << 8);
27 if (err)
28 return err;
29
30 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
31 if (err)
32 return err;
33
34 *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
35
36 return 0;
37}
38
39static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
40 u8 data)
41{
42 u16 value = (reg << 8) | data;
43
44 return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, value);
45}
46
47/**
48 * mv88e6xxx_g2_scratch_gpio_get_bit - get a bit
49 * @chip: chip private data
50 * @nr: bit index
51 * @set: is bit set?
52 */
53static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
54 int base_reg, unsigned int offset,
55 int *set)
56{
57 int reg = base_reg + (offset / 8);
58 u8 mask = (1 << (offset & 0x7));
59 u8 val;
60 int err;
61
62 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
63 if (err)
64 return err;
65
66 *set = !!(mask & val);
67
68 return 0;
69}
70
71/**
72 * mv88e6xxx_g2_scratch_gpio_set_bit - set (or clear) a bit
73 * @chip: chip private data
74 * @nr: bit index
75 * @set: set if true, clear if false
76 *
77 * Helper function for dealing with the direction and data registers.
78 */
79static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
80 int base_reg, unsigned int offset,
81 int set)
82{
83 int reg = base_reg + (offset / 8);
84 u8 mask = (1 << (offset & 0x7));
85 u8 val;
86 int err;
87
88 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
89 if (err)
90 return err;
91
92 if (set)
93 val |= mask;
94 else
95 val &= ~mask;
96
97 return mv88e6xxx_g2_scratch_write(chip, reg, val);
98}
99
100/**
101 * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
102 * @chip: chip private data
103 * @pin: gpio index
104 *
105 * Return: 0 for low, 1 for high, negative error
106 */
107static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
108 unsigned int pin)
109{
110 int val = 0;
111 int err;
112
113 err = mv88e6xxx_g2_scratch_get_bit(chip,
114 MV88E6352_G2_SCRATCH_GPIO_DATA0,
115 pin, &val);
116 if (err)
117 return err;
118
119 return val;
120}
121
122/**
123 * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
124 * @chip: chip private data
125 * @pin: gpio index
126 * @value: value to set
127 */
128static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
129 unsigned int pin, int value)
130{
131 u8 mask = (1 << (pin & 0x7));
132 int offset = (pin / 8);
133 int reg;
134
135 reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
136
137 if (value)
138 chip->gpio_data[offset] |= mask;
139 else
140 chip->gpio_data[offset] &= ~mask;
141
142 return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
143}
144
145/**
146 * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
147 * @chip: chip private data
148 * @pin: gpio index
149 *
150 * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
151 */
152static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
153 unsigned int pin)
154{
155 int val = 0;
156 int err;
157
158 err = mv88e6xxx_g2_scratch_get_bit(chip,
159 MV88E6352_G2_SCRATCH_GPIO_DIR0,
160 pin, &val);
161 if (err)
162 return err;
163
164 return val;
165}
166
167/**
168 * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
169 * @chip: chip private data
170 * @pin: gpio index
171 */
172static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
173 unsigned int pin, bool input)
174{
175 int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
176 MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
177
178 return mv88e6xxx_g2_scratch_set_bit(chip,
179 MV88E6352_G2_SCRATCH_GPIO_DIR0,
180 pin, value);
181}
182
183/**
184 * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
185 * @chip: chip private data
186 * @pin: gpio index
187 * @func: function number
188 *
189 * Note that the function numbers themselves may vary by chipset.
190 */
191static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
192 unsigned int pin, int *func)
193{
194 int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
195 int offset = (pin & 0x1) ? 4 : 0;
196 u8 mask = (0x7 << offset);
197 int err;
198 u8 val;
199
200 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
201 if (err)
202 return err;
203
204 *func = (val & mask) >> offset;
205
206 return 0;
207}
208
209/**
210 * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
211 * @chip: chip private data
212 * @pin: gpio index
213 * @func: function number
214 */
215static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
216 unsigned int pin, int func)
217{
218 int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
219 int offset = (pin & 0x1) ? 4 : 0;
220 u8 mask = (0x7 << offset);
221 int err;
222 u8 val;
223
224 err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
225 if (err)
226 return err;
227
228 val = (val & ~mask) | ((func & mask) << offset);
229
230 return mv88e6xxx_g2_scratch_write(chip, reg, val);
231}
232
233const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
234 .get_data = mv88e6352_g2_scratch_gpio_get_data,
235 .set_data = mv88e6352_g2_scratch_gpio_set_data,
236 .get_dir = mv88e6352_g2_scratch_gpio_get_dir,
237 .set_dir = mv88e6352_g2_scratch_gpio_set_dir,
238 .get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
239 .set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
240};
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
new file mode 100644
index 000000000000..b251d534b70d
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -0,0 +1,584 @@
1/*
2 * Marvell 88E6xxx Switch hardware timestamping support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Erik Hons <erik.hons@ni.com>
8 * Brandon Streiff <brandon.streiff@ni.com>
9 * Dane Wagner <dane.wagner@ni.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#include "chip.h"
18#include "global2.h"
19#include "hwtstamp.h"
20#include "ptp.h"
21#include <linux/ptp_classify.h>
22
23#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
24
25static int mv88e6xxx_port_ptp_read(struct mv88e6xxx_chip *chip, int port,
26 int addr, u16 *data, int len)
27{
28 if (!chip->info->ops->avb_ops->port_ptp_read)
29 return -EOPNOTSUPP;
30
31 return chip->info->ops->avb_ops->port_ptp_read(chip, port, addr,
32 data, len);
33}
34
35static int mv88e6xxx_port_ptp_write(struct mv88e6xxx_chip *chip, int port,
36 int addr, u16 data)
37{
38 if (!chip->info->ops->avb_ops->port_ptp_write)
39 return -EOPNOTSUPP;
40
41 return chip->info->ops->avb_ops->port_ptp_write(chip, port, addr,
42 data);
43}
44
45static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
46 u16 data)
47{
48 if (!chip->info->ops->avb_ops->ptp_write)
49 return -EOPNOTSUPP;
50
51 return chip->info->ops->avb_ops->ptp_write(chip, addr, data);
52}
53
54/* TX_TSTAMP_TIMEOUT: This limits the time spent polling for a TX
55 * timestamp. When working properly, hardware will produce a timestamp
56 * within 1ms. Software may enounter delays due to MDIO contention, so
57 * the timeout is set accordingly.
58 */
59#define TX_TSTAMP_TIMEOUT msecs_to_jiffies(20)
60
61int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
62 struct ethtool_ts_info *info)
63{
64 struct mv88e6xxx_chip *chip = ds->priv;
65
66 if (!chip->info->ptp_support)
67 return -EOPNOTSUPP;
68
69 info->so_timestamping =
70 SOF_TIMESTAMPING_TX_HARDWARE |
71 SOF_TIMESTAMPING_RX_HARDWARE |
72 SOF_TIMESTAMPING_RAW_HARDWARE;
73 info->phc_index = ptp_clock_index(chip->ptp_clock);
74 info->tx_types =
75 (1 << HWTSTAMP_TX_OFF) |
76 (1 << HWTSTAMP_TX_ON);
77 info->rx_filters =
78 (1 << HWTSTAMP_FILTER_NONE) |
79 (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
80 (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
81 (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
82 (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
83 (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
84 (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
85 (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
86 (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
87 (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
88
89 return 0;
90}
91
92static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
93 struct hwtstamp_config *config)
94{
95 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
96 bool tstamp_enable = false;
97 u16 port_config0;
98 int err;
99
100 /* Prevent the TX/RX paths from trying to interact with the
101 * timestamp hardware while we reconfigure it.
102 */
103 clear_bit_unlock(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
104
105 /* reserved for future extensions */
106 if (config->flags)
107 return -EINVAL;
108
109 switch (config->tx_type) {
110 case HWTSTAMP_TX_OFF:
111 tstamp_enable = false;
112 break;
113 case HWTSTAMP_TX_ON:
114 tstamp_enable = true;
115 break;
116 default:
117 return -ERANGE;
118 }
119
120 /* The switch supports timestamping both L2 and L4; one cannot be
121 * disabled independently of the other.
122 */
123 switch (config->rx_filter) {
124 case HWTSTAMP_FILTER_NONE:
125 tstamp_enable = false;
126 break;
127 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
128 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
129 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
130 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
131 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
132 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
133 case HWTSTAMP_FILTER_PTP_V2_EVENT:
134 case HWTSTAMP_FILTER_PTP_V2_SYNC:
135 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
136 config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
137 break;
138 case HWTSTAMP_FILTER_ALL:
139 default:
140 config->rx_filter = HWTSTAMP_FILTER_NONE;
141 return -ERANGE;
142 }
143
144 if (tstamp_enable) {
145 /* Disable transportSpecific value matching, so that packets
146 * with either 1588 (0) and 802.1AS (1) will be timestamped.
147 */
148 port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH;
149 } else {
150 /* Disable PTP. This disables both RX and TX timestamping. */
151 port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP;
152 }
153
154 mutex_lock(&chip->reg_lock);
155 err = mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
156 port_config0);
157 mutex_unlock(&chip->reg_lock);
158
159 if (err < 0)
160 return err;
161
162 /* Once hardware has been configured, enable timestamp checks
163 * in the RX/TX paths.
164 */
165 if (tstamp_enable)
166 set_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
167
168 return 0;
169}
170
171int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
172 struct ifreq *ifr)
173{
174 struct mv88e6xxx_chip *chip = ds->priv;
175 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
176 struct hwtstamp_config config;
177 int err;
178
179 if (!chip->info->ptp_support)
180 return -EOPNOTSUPP;
181
182 if (port < 0 || port >= mv88e6xxx_num_ports(chip))
183 return -EINVAL;
184
185 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
186 return -EFAULT;
187
188 err = mv88e6xxx_set_hwtstamp_config(chip, port, &config);
189 if (err)
190 return err;
191
192 /* Save the chosen configuration to be returned later. */
193 memcpy(&ps->tstamp_config, &config, sizeof(config));
194
195 return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
196 -EFAULT : 0;
197}
198
199int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
200 struct ifreq *ifr)
201{
202 struct mv88e6xxx_chip *chip = ds->priv;
203 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
204 struct hwtstamp_config *config = &ps->tstamp_config;
205
206 if (!chip->info->ptp_support)
207 return -EOPNOTSUPP;
208
209 if (port < 0 || port >= mv88e6xxx_num_ports(chip))
210 return -EINVAL;
211
212 return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
213 -EFAULT : 0;
214}
215
216/* Get the start of the PTP header in this skb */
217static u8 *parse_ptp_header(struct sk_buff *skb, unsigned int type)
218{
219 u8 *data = skb_mac_header(skb);
220 unsigned int offset = 0;
221
222 if (type & PTP_CLASS_VLAN)
223 offset += VLAN_HLEN;
224
225 switch (type & PTP_CLASS_PMASK) {
226 case PTP_CLASS_IPV4:
227 offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
228 break;
229 case PTP_CLASS_IPV6:
230 offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
231 break;
232 case PTP_CLASS_L2:
233 offset += ETH_HLEN;
234 break;
235 default:
236 return NULL;
237 }
238
239 /* Ensure that the entire header is present in this packet. */
240 if (skb->len + ETH_HLEN < offset + 34)
241 return NULL;
242
243 return data + offset;
244}
245
246/* Returns a pointer to the PTP header if the caller should time stamp,
247 * or NULL if the caller should not.
248 */
249static u8 *mv88e6xxx_should_tstamp(struct mv88e6xxx_chip *chip, int port,
250 struct sk_buff *skb, unsigned int type)
251{
252 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
253 u8 *hdr;
254
255 if (!chip->info->ptp_support)
256 return NULL;
257
258 if (port < 0 || port >= mv88e6xxx_num_ports(chip))
259 return NULL;
260
261 hdr = parse_ptp_header(skb, type);
262 if (!hdr)
263 return NULL;
264
265 if (!test_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state))
266 return NULL;
267
268 return hdr;
269}
270
271static int mv88e6xxx_ts_valid(u16 status)
272{
273 if (!(status & MV88E6XXX_PTP_TS_VALID))
274 return 0;
275 if (status & MV88E6XXX_PTP_TS_STATUS_MASK)
276 return 0;
277 return 1;
278}
279
280static int seq_match(struct sk_buff *skb, u16 ts_seqid)
281{
282 unsigned int type = SKB_PTP_TYPE(skb);
283 u8 *hdr = parse_ptp_header(skb, type);
284 __be16 *seqid;
285
286 seqid = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID);
287
288 return ts_seqid == ntohs(*seqid);
289}
290
291static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
292 struct mv88e6xxx_port_hwtstamp *ps,
293 struct sk_buff *skb, u16 reg,
294 struct sk_buff_head *rxq)
295{
296 u16 buf[4] = { 0 }, status, timelo, timehi, seq_id;
297 struct skb_shared_hwtstamps *shwt;
298 int err;
299
300 mutex_lock(&chip->reg_lock);
301 err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
302 reg, buf, ARRAY_SIZE(buf));
303 mutex_unlock(&chip->reg_lock);
304 if (err)
305 pr_err("failed to get the receive time stamp\n");
306
307 status = buf[0];
308 timelo = buf[1];
309 timehi = buf[2];
310 seq_id = buf[3];
311
312 if (status & MV88E6XXX_PTP_TS_VALID) {
313 mutex_lock(&chip->reg_lock);
314 err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
315 mutex_unlock(&chip->reg_lock);
316 if (err)
317 pr_err("failed to clear the receive status\n");
318 }
319 /* Since the device can only handle one time stamp at a time,
320 * we purge any extra frames from the queue.
321 */
322 for ( ; skb; skb = skb_dequeue(rxq)) {
323 if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
324 u64 ns = timehi << 16 | timelo;
325
326 mutex_lock(&chip->reg_lock);
327 ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
328 mutex_unlock(&chip->reg_lock);
329 shwt = skb_hwtstamps(skb);
330 memset(shwt, 0, sizeof(*shwt));
331 shwt->hwtstamp = ns_to_ktime(ns);
332 status &= ~MV88E6XXX_PTP_TS_VALID;
333 }
334 netif_rx_ni(skb);
335 }
336}
337
338static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip,
339 struct mv88e6xxx_port_hwtstamp *ps)
340{
341 struct sk_buff *skb;
342
343 skb = skb_dequeue(&ps->rx_queue);
344
345 if (skb)
346 mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR0_STS,
347 &ps->rx_queue);
348
349 skb = skb_dequeue(&ps->rx_queue2);
350 if (skb)
351 mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR1_STS,
352 &ps->rx_queue2);
353}
354
355static int is_pdelay_resp(u8 *msgtype)
356{
357 return (*msgtype & 0xf) == 3;
358}
359
360bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
361 struct sk_buff *skb, unsigned int type)
362{
363 struct mv88e6xxx_port_hwtstamp *ps;
364 struct mv88e6xxx_chip *chip;
365 u8 *hdr;
366
367 chip = ds->priv;
368 ps = &chip->port_hwtstamp[port];
369
370 if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)
371 return false;
372
373 hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
374 if (!hdr)
375 return false;
376
377 SKB_PTP_TYPE(skb) = type;
378
379 if (is_pdelay_resp(hdr))
380 skb_queue_tail(&ps->rx_queue2, skb);
381 else
382 skb_queue_tail(&ps->rx_queue, skb);
383
384 ptp_schedule_worker(chip->ptp_clock, 0);
385
386 return true;
387}
388
389static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
390 struct mv88e6xxx_port_hwtstamp *ps)
391{
392 struct skb_shared_hwtstamps shhwtstamps;
393 u16 departure_block[4], status;
394 struct sk_buff *tmp_skb;
395 u32 time_raw;
396 int err;
397 u64 ns;
398
399 if (!ps->tx_skb)
400 return 0;
401
402 mutex_lock(&chip->reg_lock);
403 err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
404 MV88E6XXX_PORT_PTP_DEP_STS,
405 departure_block,
406 ARRAY_SIZE(departure_block));
407 mutex_unlock(&chip->reg_lock);
408
409 if (err)
410 goto free_and_clear_skb;
411
412 if (!(departure_block[0] & MV88E6XXX_PTP_TS_VALID)) {
413 if (time_is_before_jiffies(ps->tx_tstamp_start +
414 TX_TSTAMP_TIMEOUT)) {
415 dev_warn(chip->dev, "p%d: clearing tx timestamp hang\n",
416 ps->port_id);
417 goto free_and_clear_skb;
418 }
419 /* The timestamp should be available quickly, while getting it
420 * is high priority and time bounded to only 10ms. A poll is
421 * warranted so restart the work.
422 */
423 return 1;
424 }
425
426 /* We have the timestamp; go ahead and clear valid now */
427 mutex_lock(&chip->reg_lock);
428 mv88e6xxx_port_ptp_write(chip, ps->port_id,
429 MV88E6XXX_PORT_PTP_DEP_STS, 0);
430 mutex_unlock(&chip->reg_lock);
431
432 status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
433 if (status != MV88E6XXX_PTP_TS_STATUS_NORMAL) {
434 dev_warn(chip->dev, "p%d: tx timestamp overrun\n", ps->port_id);
435 goto free_and_clear_skb;
436 }
437
438 if (departure_block[3] != ps->tx_seq_id) {
439 dev_warn(chip->dev, "p%d: unexpected seq. id\n", ps->port_id);
440 goto free_and_clear_skb;
441 }
442
443 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
444 time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
445 mutex_lock(&chip->reg_lock);
446 ns = timecounter_cyc2time(&chip->tstamp_tc, time_raw);
447 mutex_unlock(&chip->reg_lock);
448 shhwtstamps.hwtstamp = ns_to_ktime(ns);
449
450 dev_dbg(chip->dev,
451 "p%d: txtstamp %llx status 0x%04x skb ID 0x%04x hw ID 0x%04x\n",
452 ps->port_id, ktime_to_ns(shhwtstamps.hwtstamp),
453 departure_block[0], ps->tx_seq_id, departure_block[3]);
454
455 /* skb_complete_tx_timestamp() will free up the client to make
456 * another timestamp-able transmit. We have to be ready for it
457 * -- by clearing the ps->tx_skb "flag" -- beforehand.
458 */
459
460 tmp_skb = ps->tx_skb;
461 ps->tx_skb = NULL;
462 clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
463 skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
464
465 return 0;
466
467free_and_clear_skb:
468 dev_kfree_skb_any(ps->tx_skb);
469 ps->tx_skb = NULL;
470 clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
471
472 return 0;
473}
474
475long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
476{
477 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
478 struct dsa_switch *ds = chip->ds;
479 struct mv88e6xxx_port_hwtstamp *ps;
480 int i, restart = 0;
481
482 for (i = 0; i < ds->num_ports; i++) {
483 if (!dsa_is_user_port(ds, i))
484 continue;
485
486 ps = &chip->port_hwtstamp[i];
487 if (test_bit(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state))
488 restart |= mv88e6xxx_txtstamp_work(chip, ps);
489
490 mv88e6xxx_rxtstamp_work(chip, ps);
491 }
492
493 return restart ? 1 : -1;
494}
495
496bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
497 struct sk_buff *clone, unsigned int type)
498{
499 struct mv88e6xxx_chip *chip = ds->priv;
500 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
501 __be16 *seq_ptr;
502 u8 *hdr;
503
504 if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
505 return false;
506
507 hdr = mv88e6xxx_should_tstamp(chip, port, clone, type);
508 if (!hdr)
509 return false;
510
511 seq_ptr = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID);
512
513 if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
514 &ps->state))
515 return false;
516
517 ps->tx_skb = clone;
518 ps->tx_tstamp_start = jiffies;
519 ps->tx_seq_id = be16_to_cpup(seq_ptr);
520
521 ptp_schedule_worker(chip->ptp_clock, 0);
522 return true;
523}
524
525static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
526{
527 struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
528
529 ps->port_id = port;
530
531 skb_queue_head_init(&ps->rx_queue);
532 skb_queue_head_init(&ps->rx_queue2);
533
534 return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
535 MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP);
536}
537
538int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
539{
540 int err;
541 int i;
542
543 /* Disable timestamping on all ports. */
544 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
545 err = mv88e6xxx_hwtstamp_port_setup(chip, i);
546 if (err)
547 return err;
548 }
549
550 /* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
551 * timestamp. This affects all ports that have timestamping enabled,
552 * but the timestamp config is per-port; thus we configure all events
553 * here and only support the HWTSTAMP_FILTER_*_EVENT filter types.
554 */
555 err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_MSGTYPE,
556 MV88E6XXX_PTP_MSGTYPE_ALL_EVENT);
557 if (err)
558 return err;
559
560 /* Use ARRIVAL1 for peer delay response messages. */
561 err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_TS_ARRIVAL_PTR,
562 MV88E6XXX_PTP_MSGTYPE_PDLAY_RES);
563 if (err)
564 return err;
565
566 /* 88E6341 devices default to timestamping at the PHY, but this has
567 * a hardware issue that results in unreliable timestamps. Force
568 * these devices to timestamp at the MAC.
569 */
570 if (chip->info->family == MV88E6XXX_FAMILY_6341) {
571 u16 val = MV88E6341_PTP_CFG_UPDATE |
572 MV88E6341_PTP_CFG_MODE_IDX |
573 MV88E6341_PTP_CFG_MODE_TS_AT_MAC;
574 err = mv88e6xxx_ptp_write(chip, MV88E6341_PTP_CFG, val);
575 if (err)
576 return err;
577 }
578
579 return 0;
580}
581
582void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
583{
584}
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
new file mode 100644
index 000000000000..bc71c9212a08
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -0,0 +1,172 @@
1/*
2 * Marvell 88E6xxx Switch hardware timestamping support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Erik Hons <erik.hons@ni.com>
8 * Brandon Streiff <brandon.streiff@ni.com>
9 * Dane Wagner <dane.wagner@ni.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#ifndef _MV88E6XXX_HWTSTAMP_H
18#define _MV88E6XXX_HWTSTAMP_H
19
20#include "chip.h"
21
22/* Global PTP registers */
23/* Offset 0x00: PTP EtherType */
24#define MV88E6XXX_PTP_ETHERTYPE 0x00
25
26/* Offset 0x01: Message Type Timestamp Enables */
27#define MV88E6XXX_PTP_MSGTYPE 0x01
28#define MV88E6XXX_PTP_MSGTYPE_SYNC 0x0001
29#define MV88E6XXX_PTP_MSGTYPE_DELAY_REQ 0x0002
30#define MV88E6XXX_PTP_MSGTYPE_PDLAY_REQ 0x0004
31#define MV88E6XXX_PTP_MSGTYPE_PDLAY_RES 0x0008
32#define MV88E6XXX_PTP_MSGTYPE_ALL_EVENT 0x000f
33
34/* Offset 0x02: Timestamp Arrival Capture Pointers */
35#define MV88E6XXX_PTP_TS_ARRIVAL_PTR 0x02
36
37/* Offset 0x07: PTP Global Configuration */
38#define MV88E6341_PTP_CFG 0x07
39#define MV88E6341_PTP_CFG_UPDATE 0x8000
40#define MV88E6341_PTP_CFG_IDX_MASK 0x7f00
41#define MV88E6341_PTP_CFG_DATA_MASK 0x00ff
42#define MV88E6341_PTP_CFG_MODE_IDX 0x0
43#define MV88E6341_PTP_CFG_MODE_TS_AT_PHY 0x00
44#define MV88E6341_PTP_CFG_MODE_TS_AT_MAC 0x80
45
46/* Offset 0x08: PTP Interrupt Status */
47#define MV88E6XXX_PTP_IRQ_STATUS 0x08
48
49/* Per-Port PTP Registers */
50/* Offset 0x00: PTP Configuration 0 */
51#define MV88E6XXX_PORT_PTP_CFG0 0x00
52#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_SHIFT 12
53#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_MASK 0xf000
54#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_1588 0x0000
55#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_8021AS 0x1000
56#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH 0x0800
57#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_OVERWRITE 0x0002
58#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP 0x0001
59
60/* Offset 0x01: PTP Configuration 1 */
61#define MV88E6XXX_PORT_PTP_CFG1 0x01
62
63/* Offset 0x02: PTP Configuration 2 */
64#define MV88E6XXX_PORT_PTP_CFG2 0x02
65#define MV88E6XXX_PORT_PTP_CFG2_EMBED_ARRIVAL 0x1000
66#define MV88E6XXX_PORT_PTP_CFG2_DEP_IRQ_EN 0x0002
67#define MV88E6XXX_PORT_PTP_CFG2_ARR_IRQ_EN 0x0001
68
69/* Offset 0x03: PTP LED Configuration */
70#define MV88E6XXX_PORT_PTP_LED_CFG 0x03
71
72/* Offset 0x08: PTP Arrival 0 Status */
73#define MV88E6XXX_PORT_PTP_ARR0_STS 0x08
74
75/* Offset 0x09/0x0A: PTP Arrival 0 Time */
76#define MV88E6XXX_PORT_PTP_ARR0_TIME_LO 0x09
77#define MV88E6XXX_PORT_PTP_ARR0_TIME_HI 0x0a
78
79/* Offset 0x0B: PTP Arrival 0 Sequence ID */
80#define MV88E6XXX_PORT_PTP_ARR0_SEQID 0x0b
81
82/* Offset 0x0C: PTP Arrival 1 Status */
83#define MV88E6XXX_PORT_PTP_ARR1_STS 0x0c
84
85/* Offset 0x0D/0x0E: PTP Arrival 1 Time */
86#define MV88E6XXX_PORT_PTP_ARR1_TIME_LO 0x0d
87#define MV88E6XXX_PORT_PTP_ARR1_TIME_HI 0x0e
88
89/* Offset 0x0F: PTP Arrival 1 Sequence ID */
90#define MV88E6XXX_PORT_PTP_ARR1_SEQID 0x0f
91
92/* Offset 0x10: PTP Departure Status */
93#define MV88E6XXX_PORT_PTP_DEP_STS 0x10
94
95/* Offset 0x11/0x12: PTP Deperture Time */
96#define MV88E6XXX_PORT_PTP_DEP_TIME_LO 0x11
97#define MV88E6XXX_PORT_PTP_DEP_TIME_HI 0x12
98
99/* Offset 0x13: PTP Departure Sequence ID */
100#define MV88E6XXX_PORT_PTP_DEP_SEQID 0x13
101
102/* Status fields for arrival and depature timestamp status registers */
103#define MV88E6XXX_PTP_TS_STATUS_MASK 0x0006
104#define MV88E6XXX_PTP_TS_STATUS_NORMAL 0x0000
105#define MV88E6XXX_PTP_TS_STATUS_OVERWITTEN 0x0002
106#define MV88E6XXX_PTP_TS_STATUS_DISCARDED 0x0004
107#define MV88E6XXX_PTP_TS_VALID 0x0001
108
109#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
110
111int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
112 struct ifreq *ifr);
113int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
114 struct ifreq *ifr);
115
116bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
117 struct sk_buff *clone, unsigned int type);
118bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
119 struct sk_buff *clone, unsigned int type);
120
121int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
122 struct ethtool_ts_info *info);
123
124int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
125void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
126
127#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
128
129static inline int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds,
130 int port, struct ifreq *ifr)
131{
132 return -EOPNOTSUPP;
133}
134
135static inline int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds,
136 int port, struct ifreq *ifr)
137{
138 return -EOPNOTSUPP;
139}
140
141static inline bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
142 struct sk_buff *clone,
143 unsigned int type)
144{
145 return false;
146}
147
148static inline bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
149 struct sk_buff *clone,
150 unsigned int type)
151{
152 return false;
153}
154
155static inline int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
156 struct ethtool_ts_info *info)
157{
158 return -EOPNOTSUPP;
159}
160
161static inline int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
162{
163 return 0;
164}
165
166static inline void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
167{
168}
169
170#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
171
172#endif /* _MV88E6XXX_HWTSTAMP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
new file mode 100644
index 000000000000..bd85e2c390e1
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -0,0 +1,381 @@
1/*
2 * Marvell 88E6xxx Switch PTP support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Erik Hons <erik.hons@ni.com>
8 * Brandon Streiff <brandon.streiff@ni.com>
9 * Dane Wagner <dane.wagner@ni.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#include "chip.h"
18#include "global2.h"
19#include "ptp.h"
20
21/* Raw timestamps are in units of 8-ns clock periods. */
22#define CC_SHIFT 28
23#define CC_MULT (8 << CC_SHIFT)
24#define CC_MULT_NUM (1 << 9)
25#define CC_MULT_DEM 15625ULL
26
27#define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100)
28
29#define cc_to_chip(cc) container_of(cc, struct mv88e6xxx_chip, tstamp_cc)
30#define dw_overflow_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
31 overflow_work)
32#define dw_tai_event_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
33 tai_event_work)
34
35static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
36 u16 *data, int len)
37{
38 if (!chip->info->ops->avb_ops->tai_read)
39 return -EOPNOTSUPP;
40
41 return chip->info->ops->avb_ops->tai_read(chip, addr, data, len);
42}
43
44static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data)
45{
46 if (!chip->info->ops->avb_ops->tai_write)
47 return -EOPNOTSUPP;
48
49 return chip->info->ops->avb_ops->tai_write(chip, addr, data);
50}
51
52/* TODO: places where this are called should be using pinctrl */
53static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
54 int func, int input)
55{
56 int err;
57
58 if (!chip->info->ops->gpio_ops)
59 return -EOPNOTSUPP;
60
61 err = chip->info->ops->gpio_ops->set_dir(chip, pin, input);
62 if (err)
63 return err;
64
65 return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
66}
67
68static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
69{
70 struct mv88e6xxx_chip *chip = cc_to_chip(cc);
71 u16 phc_time[2];
72 int err;
73
74 err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_TIME_LO, phc_time,
75 ARRAY_SIZE(phc_time));
76 if (err)
77 return 0;
78 else
79 return ((u32)phc_time[1] << 16) | phc_time[0];
80}
81
82/* mv88e6xxx_config_eventcap - configure TAI event capture
83 * @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external)
84 * @rising: zero for falling-edge trigger, else rising-edge trigger
85 *
86 * This will also reset the capture sequence counter.
87 */
88static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event,
89 int rising)
90{
91 u16 global_config;
92 u16 cap_config;
93 int err;
94
95 chip->evcap_config = MV88E6XXX_TAI_CFG_CAP_OVERWRITE |
96 MV88E6XXX_TAI_CFG_CAP_CTR_START;
97 if (!rising)
98 chip->evcap_config |= MV88E6XXX_TAI_CFG_EVREQ_FALLING;
99
100 global_config = (chip->evcap_config | chip->trig_config);
101 err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_CFG, global_config);
102 if (err)
103 return err;
104
105 if (event == PTP_CLOCK_PPS) {
106 cap_config = MV88E6XXX_TAI_EVENT_STATUS_CAP_TRIG;
107 } else if (event == PTP_CLOCK_EXTTS) {
108 /* if STATUS_CAP_TRIG is unset we capture PTP_EVREQ events */
109 cap_config = 0;
110 } else {
111 return -EINVAL;
112 }
113
114 /* Write the capture config; this also clears the capture counter */
115 err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS,
116 cap_config);
117
118 return err;
119}
120
121static void mv88e6xxx_tai_event_work(struct work_struct *ugly)
122{
123 struct delayed_work *dw = to_delayed_work(ugly);
124 struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw);
125 struct ptp_clock_event ev;
126 u16 status[4];
127 u32 raw_ts;
128 int err;
129
130 mutex_lock(&chip->reg_lock);
131 err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS,
132 status, ARRAY_SIZE(status));
133 mutex_unlock(&chip->reg_lock);
134
135 if (err) {
136 dev_err(chip->dev, "failed to read TAI status register\n");
137 return;
138 }
139 if (status[0] & MV88E6XXX_TAI_EVENT_STATUS_ERROR) {
140 dev_warn(chip->dev, "missed event capture\n");
141 return;
142 }
143 if (!(status[0] & MV88E6XXX_TAI_EVENT_STATUS_VALID))
144 goto out;
145
146 raw_ts = ((u32)status[2] << 16) | status[1];
147
148 /* Clear the valid bit so the next timestamp can come in */
149 status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID;
150 mutex_lock(&chip->reg_lock);
151 err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]);
152 mutex_unlock(&chip->reg_lock);
153
154 /* This is an external timestamp */
155 ev.type = PTP_CLOCK_EXTTS;
156
157 /* We only have one timestamping channel. */
158 ev.index = 0;
159 mutex_lock(&chip->reg_lock);
160 ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts);
161 mutex_unlock(&chip->reg_lock);
162
163 ptp_clock_event(chip->ptp_clock, &ev);
164out:
165 schedule_delayed_work(&chip->tai_event_work, TAI_EVENT_WORK_INTERVAL);
166}
167
168static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
169{
170 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
171 int neg_adj = 0;
172 u32 diff, mult;
173 u64 adj;
174
175 if (scaled_ppm < 0) {
176 neg_adj = 1;
177 scaled_ppm = -scaled_ppm;
178 }
179 mult = CC_MULT;
180 adj = CC_MULT_NUM;
181 adj *= scaled_ppm;
182 diff = div_u64(adj, CC_MULT_DEM);
183
184 mutex_lock(&chip->reg_lock);
185
186 timecounter_read(&chip->tstamp_tc);
187 chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
188
189 mutex_unlock(&chip->reg_lock);
190
191 return 0;
192}
193
194static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
195{
196 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
197
198 mutex_lock(&chip->reg_lock);
199 timecounter_adjtime(&chip->tstamp_tc, delta);
200 mutex_unlock(&chip->reg_lock);
201
202 return 0;
203}
204
205static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
206 struct timespec64 *ts)
207{
208 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
209 u64 ns;
210
211 mutex_lock(&chip->reg_lock);
212 ns = timecounter_read(&chip->tstamp_tc);
213 mutex_unlock(&chip->reg_lock);
214
215 *ts = ns_to_timespec64(ns);
216
217 return 0;
218}
219
220static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
221 const struct timespec64 *ts)
222{
223 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
224 u64 ns;
225
226 ns = timespec64_to_ns(ts);
227
228 mutex_lock(&chip->reg_lock);
229 timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
230 mutex_unlock(&chip->reg_lock);
231
232 return 0;
233}
234
235static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
236 struct ptp_clock_request *rq, int on)
237{
238 int rising = (rq->extts.flags & PTP_RISING_EDGE);
239 int func;
240 int pin;
241 int err;
242
243 pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, rq->extts.index);
244
245 if (pin < 0)
246 return -EBUSY;
247
248 mutex_lock(&chip->reg_lock);
249
250 if (on) {
251 func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
252
253 err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
254 if (err)
255 goto out;
256
257 schedule_delayed_work(&chip->tai_event_work,
258 TAI_EVENT_WORK_INTERVAL);
259
260 err = mv88e6xxx_config_eventcap(chip, PTP_CLOCK_EXTTS, rising);
261 } else {
262 func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
263
264 err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
265
266 cancel_delayed_work_sync(&chip->tai_event_work);
267 }
268
269out:
270 mutex_unlock(&chip->reg_lock);
271
272 return err;
273}
274
275static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
276 struct ptp_clock_request *rq, int on)
277{
278 struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
279
280 switch (rq->type) {
281 case PTP_CLK_REQ_EXTTS:
282 return mv88e6xxx_ptp_enable_extts(chip, rq, on);
283 default:
284 return -EOPNOTSUPP;
285 }
286}
287
288static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
289 enum ptp_pin_function func, unsigned int chan)
290{
291 switch (func) {
292 case PTP_PF_NONE:
293 case PTP_PF_EXTTS:
294 break;
295 case PTP_PF_PEROUT:
296 case PTP_PF_PHYSYNC:
297 return -EOPNOTSUPP;
298 }
299 return 0;
300}
301
302/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
303 * seconds; this task forces periodic reads so that we don't miss any.
304 */
305#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 16)
306static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
307{
308 struct delayed_work *dw = to_delayed_work(work);
309 struct mv88e6xxx_chip *chip = dw_overflow_to_chip(dw);
310 struct timespec64 ts;
311
312 mv88e6xxx_ptp_gettime(&chip->ptp_clock_info, &ts);
313
314 schedule_delayed_work(&chip->overflow_work,
315 MV88E6XXX_TAI_OVERFLOW_PERIOD);
316}
317
318int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
319{
320 int i;
321
322 /* Set up the cycle counter */
323 memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
324 chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read;
325 chip->tstamp_cc.mask = CYCLECOUNTER_MASK(32);
326 chip->tstamp_cc.mult = CC_MULT;
327 chip->tstamp_cc.shift = CC_SHIFT;
328
329 timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc,
330 ktime_to_ns(ktime_get_real()));
331
332 INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
333 INIT_DELAYED_WORK(&chip->tai_event_work, mv88e6xxx_tai_event_work);
334
335 chip->ptp_clock_info.owner = THIS_MODULE;
336 snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
337 dev_name(chip->dev));
338 chip->ptp_clock_info.max_adj = 1000000;
339
340 chip->ptp_clock_info.n_ext_ts = 1;
341 chip->ptp_clock_info.n_per_out = 0;
342 chip->ptp_clock_info.n_pins = mv88e6xxx_num_gpio(chip);
343 chip->ptp_clock_info.pps = 0;
344
345 for (i = 0; i < chip->ptp_clock_info.n_pins; ++i) {
346 struct ptp_pin_desc *ppd = &chip->pin_config[i];
347
348 snprintf(ppd->name, sizeof(ppd->name), "mv88e6xxx_gpio%d", i);
349 ppd->index = i;
350 ppd->func = PTP_PF_NONE;
351 }
352 chip->ptp_clock_info.pin_config = chip->pin_config;
353
354 chip->ptp_clock_info.adjfine = mv88e6xxx_ptp_adjfine;
355 chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime;
356 chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
357 chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
358 chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable;
359 chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
360 chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
361
362 chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
363 if (IS_ERR(chip->ptp_clock))
364 return PTR_ERR(chip->ptp_clock);
365
366 schedule_delayed_work(&chip->overflow_work,
367 MV88E6XXX_TAI_OVERFLOW_PERIOD);
368
369 return 0;
370}
371
372void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
373{
374 if (chip->ptp_clock) {
375 cancel_delayed_work_sync(&chip->overflow_work);
376 cancel_delayed_work_sync(&chip->tai_event_work);
377
378 ptp_clock_unregister(chip->ptp_clock);
379 chip->ptp_clock = NULL;
380 }
381}
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
new file mode 100644
index 000000000000..992818ade746
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -0,0 +1,108 @@
1/*
2 * Marvell 88E6xxx Switch PTP support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2017 National Instruments
7 * Erik Hons <erik.hons@ni.com>
8 * Brandon Streiff <brandon.streiff@ni.com>
9 * Dane Wagner <dane.wagner@ni.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#ifndef _MV88E6XXX_PTP_H
18#define _MV88E6XXX_PTP_H
19
20#include "chip.h"
21
22/* Offset 0x00: TAI Global Config */
23#define MV88E6XXX_TAI_CFG 0x00
24#define MV88E6XXX_TAI_CFG_CAP_OVERWRITE 0x8000
25#define MV88E6XXX_TAI_CFG_CAP_CTR_START 0x4000
26#define MV88E6XXX_TAI_CFG_EVREQ_FALLING 0x2000
27#define MV88E6XXX_TAI_CFG_TRIG_ACTIVE_LO 0x1000
28#define MV88E6XXX_TAI_CFG_IRL_ENABLE 0x0400
29#define MV88E6XXX_TAI_CFG_TRIG_IRQ_EN 0x0200
30#define MV88E6XXX_TAI_CFG_EVREQ_IRQ_EN 0x0100
31#define MV88E6XXX_TAI_CFG_TRIG_LOCK 0x0080
32#define MV88E6XXX_TAI_CFG_BLOCK_UPDATE 0x0008
33#define MV88E6XXX_TAI_CFG_MULTI_PTP 0x0004
34#define MV88E6XXX_TAI_CFG_TRIG_MODE_ONESHOT 0x0002
35#define MV88E6XXX_TAI_CFG_TRIG_ENABLE 0x0001
36
37/* Offset 0x01: Timestamp Clock Period (ps) */
38#define MV88E6XXX_TAI_CLOCK_PERIOD 0x01
39
40/* Offset 0x02/0x03: Trigger Generation Amount */
41#define MV88E6XXX_TAI_TRIG_GEN_AMOUNT_LO 0x02
42#define MV88E6XXX_TAI_TRIG_GEN_AMOUNT_HI 0x03
43
44/* Offset 0x04: Clock Compensation */
45#define MV88E6XXX_TAI_TRIG_CLOCK_COMP 0x04
46
47/* Offset 0x05: Trigger Configuration */
48#define MV88E6XXX_TAI_TRIG_CFG 0x05
49
50/* Offset 0x06: Ingress Rate Limiter Clock Generation Amount */
51#define MV88E6XXX_TAI_IRL_AMOUNT 0x06
52
53/* Offset 0x07: Ingress Rate Limiter Compensation */
54#define MV88E6XXX_TAI_IRL_COMP 0x07
55
56/* Offset 0x08: Ingress Rate Limiter Compensation */
57#define MV88E6XXX_TAI_IRL_COMP_PS 0x08
58
59/* Offset 0x09: Event Status */
60#define MV88E6XXX_TAI_EVENT_STATUS 0x09
61#define MV88E6XXX_TAI_EVENT_STATUS_CAP_TRIG 0x4000
62#define MV88E6XXX_TAI_EVENT_STATUS_ERROR 0x0200
63#define MV88E6XXX_TAI_EVENT_STATUS_VALID 0x0100
64#define MV88E6XXX_TAI_EVENT_STATUS_CTR_MASK 0x00ff
65
66/* Offset 0x0A/0x0B: Event Time */
67#define MV88E6XXX_TAI_EVENT_TIME_LO 0x0a
68#define MV88E6XXX_TAI_EVENT_TYPE_HI 0x0b
69
70/* Offset 0x0E/0x0F: PTP Global Time */
71#define MV88E6XXX_TAI_TIME_LO 0x0e
72#define MV88E6XXX_TAI_TIME_HI 0x0f
73
74/* Offset 0x10/0x11: Trig Generation Time */
75#define MV88E6XXX_TAI_TRIG_TIME_LO 0x10
76#define MV88E6XXX_TAI_TRIG_TIME_HI 0x11
77
78/* Offset 0x12: Lock Status */
79#define MV88E6XXX_TAI_LOCK_STATUS 0x12
80
81#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
82
83long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
84int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip);
85void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
86
87#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
88 ptp_clock_info)
89
90#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
91
92static long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
93{
94 return -1;
95}
96
97static inline int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
98{
99 return 0;
100}
101
102static void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
103{
104}
105
106#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
107
108#endif /* _MV88E6XXX_PTP_H */
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
index a079656b614c..059242030631 100644
--- a/include/linux/ptp_classify.h
+++ b/include/linux/ptp_classify.h
@@ -75,5 +75,9 @@ void __init ptp_classifier_init(void);
75static inline void ptp_classifier_init(void) 75static inline void ptp_classifier_init(void)
76{ 76{
77} 77}
78static inline unsigned int ptp_classify_raw(struct sk_buff *skb)
79{
80 return PTP_CLASS_NONE;
81}
78#endif 82#endif
79#endif /* _PTP_CLASSIFY_H_ */ 83#endif /* _PTP_CLASSIFY_H_ */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6cb602dd970c..0ad17b63684d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -19,6 +19,7 @@
19#include <linux/workqueue.h> 19#include <linux/workqueue.h>
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/ethtool.h> 21#include <linux/ethtool.h>
22#include <linux/net_tstamp.h>
22#include <net/devlink.h> 23#include <net/devlink.h>
23#include <net/switchdev.h> 24#include <net/switchdev.h>
24 25
@@ -101,6 +102,7 @@ struct dsa_platform_data {
101}; 102};
102 103
103struct packet_type; 104struct packet_type;
105struct dsa_switch;
104 106
105struct dsa_device_ops { 107struct dsa_device_ops {
106 struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); 108 struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -368,6 +370,12 @@ struct dsa_switch_ops {
368 struct ethtool_wolinfo *w); 370 struct ethtool_wolinfo *w);
369 371
370 /* 372 /*
373 * ethtool timestamp info
374 */
375 int (*get_ts_info)(struct dsa_switch *ds, int port,
376 struct ethtool_ts_info *ts);
377
378 /*
371 * Suspend and resume 379 * Suspend and resume
372 */ 380 */
373 int (*suspend)(struct dsa_switch *ds); 381 int (*suspend)(struct dsa_switch *ds);
@@ -469,6 +477,18 @@ struct dsa_switch_ops {
469 int port, struct net_device *br); 477 int port, struct net_device *br);
470 void (*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index, 478 void (*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index,
471 int port, struct net_device *br); 479 int port, struct net_device *br);
480
481 /*
482 * PTP functionality
483 */
484 int (*port_hwtstamp_get)(struct dsa_switch *ds, int port,
485 struct ifreq *ifr);
486 int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
487 struct ifreq *ifr);
488 bool (*port_txtstamp)(struct dsa_switch *ds, int port,
489 struct sk_buff *clone, unsigned int type);
490 bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
491 struct sk_buff *skb, unsigned int type);
472}; 492};
473 493
474struct dsa_switch_driver { 494struct dsa_switch_driver {
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 6a9d0f50fbee..e63c554e0623 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -23,6 +23,7 @@
23#include <linux/netdevice.h> 23#include <linux/netdevice.h>
24#include <linux/sysfs.h> 24#include <linux/sysfs.h>
25#include <linux/phy_fixed.h> 25#include <linux/phy_fixed.h>
26#include <linux/ptp_classify.h>
26#include <linux/gpio/consumer.h> 27#include <linux/gpio/consumer.h>
27#include <linux/etherdevice.h> 28#include <linux/etherdevice.h>
28 29
@@ -122,6 +123,38 @@ struct net_device *dsa_dev_to_net_device(struct device *dev)
122} 123}
123EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); 124EXPORT_SYMBOL_GPL(dsa_dev_to_net_device);
124 125
126/* Determine if we should defer delivery of skb until we have a rx timestamp.
127 *
128 * Called from dsa_switch_rcv. For now, this will only work if tagging is
129 * enabled on the switch. Normally the MAC driver would retrieve the hardware
130 * timestamp when it reads the packet out of the hardware. However in a DSA
131 * switch, the DSA driver owning the interface to which the packet is
132 * delivered is never notified unless we do so here.
133 */
134static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p,
135 struct sk_buff *skb)
136{
137 struct dsa_switch *ds = p->dp->ds;
138 unsigned int type;
139
140 if (skb_headroom(skb) < ETH_HLEN)
141 return false;
142
143 __skb_push(skb, ETH_HLEN);
144
145 type = ptp_classify_raw(skb);
146
147 __skb_pull(skb, ETH_HLEN);
148
149 if (type == PTP_CLASS_NONE)
150 return false;
151
152 if (likely(ds->ops->port_rxtstamp))
153 return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type);
154
155 return false;
156}
157
125static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, 158static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
126 struct packet_type *pt, struct net_device *unused) 159 struct packet_type *pt, struct net_device *unused)
127{ 160{
@@ -157,6 +190,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
157 s->rx_bytes += skb->len; 190 s->rx_bytes += skb->len;
158 u64_stats_update_end(&s->syncp); 191 u64_stats_update_end(&s->syncp);
159 192
193 if (dsa_skb_defer_rx_timestamp(p, skb))
194 return 0;
195
160 netif_receive_skb(skb); 196 netif_receive_skb(skb);
161 197
162 return 0; 198 return 0;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index f52307296de4..3376dad6dcfd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -21,6 +21,7 @@
21#include <net/tc_act/tc_mirred.h> 21#include <net/tc_act/tc_mirred.h>
22#include <linux/if_bridge.h> 22#include <linux/if_bridge.h>
23#include <linux/netpoll.h> 23#include <linux/netpoll.h>
24#include <linux/ptp_classify.h>
24 25
25#include "dsa_priv.h" 26#include "dsa_priv.h"
26 27
@@ -255,6 +256,22 @@ dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
255 256
256static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 257static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
257{ 258{
259 struct dsa_slave_priv *p = netdev_priv(dev);
260 struct dsa_switch *ds = p->dp->ds;
261 int port = p->dp->index;
262
263 /* Pass through to switch driver if it supports timestamping */
264 switch (cmd) {
265 case SIOCGHWTSTAMP:
266 if (ds->ops->port_hwtstamp_get)
267 return ds->ops->port_hwtstamp_get(ds, port, ifr);
268 break;
269 case SIOCSHWTSTAMP:
270 if (ds->ops->port_hwtstamp_set)
271 return ds->ops->port_hwtstamp_set(ds, port, ifr);
272 break;
273 }
274
258 if (!dev->phydev) 275 if (!dev->phydev)
259 return -ENODEV; 276 return -ENODEV;
260 277
@@ -385,6 +402,30 @@ static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
385 return NETDEV_TX_OK; 402 return NETDEV_TX_OK;
386} 403}
387 404
405static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
406 struct sk_buff *skb)
407{
408 struct dsa_switch *ds = p->dp->ds;
409 struct sk_buff *clone;
410 unsigned int type;
411
412 type = ptp_classify_raw(skb);
413 if (type == PTP_CLASS_NONE)
414 return;
415
416 if (!ds->ops->port_txtstamp)
417 return;
418
419 clone = skb_clone_sk(skb);
420 if (!clone)
421 return;
422
423 if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type))
424 return;
425
426 kfree_skb(clone);
427}
428
388static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) 429static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
389{ 430{
390 struct dsa_slave_priv *p = netdev_priv(dev); 431 struct dsa_slave_priv *p = netdev_priv(dev);
@@ -397,6 +438,11 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
397 s->tx_bytes += skb->len; 438 s->tx_bytes += skb->len;
398 u64_stats_update_end(&s->syncp); 439 u64_stats_update_end(&s->syncp);
399 440
441 /* Identify PTP protocol packets, clone them, and pass them to the
442 * switch driver
443 */
444 dsa_skb_tx_timestamp(p, skb);
445
400 /* Transmit function may have to reallocate the original SKB, 446 /* Transmit function may have to reallocate the original SKB,
401 * in which case it must have freed it. Only free it here on error. 447 * in which case it must have freed it. Only free it here on error.
402 */ 448 */
@@ -918,6 +964,18 @@ static int dsa_slave_set_rxnfc(struct net_device *dev,
918 return ds->ops->set_rxnfc(ds, dp->index, nfc); 964 return ds->ops->set_rxnfc(ds, dp->index, nfc);
919} 965}
920 966
967static int dsa_slave_get_ts_info(struct net_device *dev,
968 struct ethtool_ts_info *ts)
969{
970 struct dsa_slave_priv *p = netdev_priv(dev);
971 struct dsa_switch *ds = p->dp->ds;
972
973 if (!ds->ops->get_ts_info)
974 return -EOPNOTSUPP;
975
976 return ds->ops->get_ts_info(ds, p->dp->index, ts);
977}
978
921static const struct ethtool_ops dsa_slave_ethtool_ops = { 979static const struct ethtool_ops dsa_slave_ethtool_ops = {
922 .get_drvinfo = dsa_slave_get_drvinfo, 980 .get_drvinfo = dsa_slave_get_drvinfo,
923 .get_regs_len = dsa_slave_get_regs_len, 981 .get_regs_len = dsa_slave_get_regs_len,
@@ -938,6 +996,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
938 .set_link_ksettings = phy_ethtool_set_link_ksettings, 996 .set_link_ksettings = phy_ethtool_set_link_ksettings,
939 .get_rxnfc = dsa_slave_get_rxnfc, 997 .get_rxnfc = dsa_slave_get_rxnfc,
940 .set_rxnfc = dsa_slave_set_rxnfc, 998 .set_rxnfc = dsa_slave_set_rxnfc,
999 .get_ts_info = dsa_slave_get_ts_info,
941}; 1000};
942 1001
943/* legacy way, bypassing the bridge *****************************************/ 1002/* legacy way, bypassing the bridge *****************************************/