13
13
#include <linux/dma/ti-cppi5.h>
14
14
#include <linux/etherdevice.h>
15
15
#include <linux/genalloc.h>
16
+ #include <linux/if_hsr.h>
16
17
#include <linux/if_vlan.h>
17
18
#include <linux/interrupt.h>
18
19
#include <linux/kernel.h>
40
41
#define DEFAULT_PORT_MASK 1
41
42
#define DEFAULT_UNTAG_MASK 1
42
43
44
+ #define NETIF_PRUETH_HSR_OFFLOAD_FEATURES NETIF_F_HW_HSR_FWD
45
+
43
46
/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
44
47
#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
45
48
@@ -118,6 +121,19 @@ static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)
118
121
return IRQ_HANDLED ;
119
122
}
120
123
124
+ static struct icssg_firmwares icssg_hsr_firmwares [] = {
125
+ {
126
+ .pru = "ti-pruss/am65x-sr2-pru0-pruhsr-fw.elf" ,
127
+ .rtu = "ti-pruss/am65x-sr2-rtu0-pruhsr-fw.elf" ,
128
+ .txpru = "ti-pruss/am65x-sr2-txpru0-pruhsr-fw.elf" ,
129
+ },
130
+ {
131
+ .pru = "ti-pruss/am65x-sr2-pru1-pruhsr-fw.elf" ,
132
+ .rtu = "ti-pruss/am65x-sr2-rtu1-pruhsr-fw.elf" ,
133
+ .txpru = "ti-pruss/am65x-sr2-txpru1-pruhsr-fw.elf" ,
134
+ }
135
+ };
136
+
121
137
static struct icssg_firmwares icssg_switch_firmwares [] = {
122
138
{
123
139
.pru = "ti-pruss/am65x-sr2-pru0-prusw-fw.elf" ,
@@ -152,6 +168,8 @@ static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
152
168
153
169
if (prueth -> is_switch_mode )
154
170
firmwares = icssg_switch_firmwares ;
171
+ else if (prueth -> is_hsr_offload_mode )
172
+ firmwares = icssg_hsr_firmwares ;
155
173
else
156
174
firmwares = icssg_emac_firmwares ;
157
175
@@ -865,6 +883,7 @@ static int prueth_netdev_init(struct prueth *prueth,
865
883
ndev -> ethtool_ops = & icssg_ethtool_ops ;
866
884
ndev -> hw_features = NETIF_F_SG ;
867
885
ndev -> features = ndev -> hw_features ;
886
+ ndev -> hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES ;
868
887
869
888
netif_napi_add (ndev , & emac -> napi_rx , icssg_napi_rx_poll );
870
889
hrtimer_init (& emac -> rx_hrtimer , CLOCK_MONOTONIC ,
@@ -953,7 +972,7 @@ static void prueth_emac_restart(struct prueth *prueth)
953
972
netif_device_attach (emac1 -> ndev );
954
973
}
955
974
956
- static void icssg_enable_switch_mode (struct prueth * prueth )
975
+ static void icssg_change_mode (struct prueth * prueth )
957
976
{
958
977
struct prueth_emac * emac ;
959
978
int mac ;
@@ -973,8 +992,13 @@ static void icssg_enable_switch_mode(struct prueth *prueth)
973
992
BIT (emac -> port_id ) | DEFAULT_PORT_MASK ,
974
993
BIT (emac -> port_id ) | DEFAULT_UNTAG_MASK ,
975
994
true);
995
+ if (prueth -> is_hsr_offload_mode )
996
+ icssg_vtbl_modify (emac , DEFAULT_VID ,
997
+ DEFAULT_PORT_MASK ,
998
+ DEFAULT_UNTAG_MASK , true);
976
999
icssg_set_pvid (prueth , emac -> port_vlan , emac -> port_id );
977
- icssg_set_port_state (emac , ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE );
1000
+ if (prueth -> is_switch_mode )
1001
+ icssg_set_port_state (emac , ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE );
978
1002
}
979
1003
}
980
1004
}
@@ -1012,7 +1036,7 @@ static int prueth_netdevice_port_link(struct net_device *ndev,
1012
1036
prueth -> is_switch_mode = true;
1013
1037
prueth -> default_vlan = 1 ;
1014
1038
emac -> port_vlan = prueth -> default_vlan ;
1015
- icssg_enable_switch_mode (prueth );
1039
+ icssg_change_mode (prueth );
1016
1040
}
1017
1041
}
1018
1042
@@ -1040,13 +1064,70 @@ static void prueth_netdevice_port_unlink(struct net_device *ndev)
1040
1064
prueth -> hw_bridge_dev = NULL ;
1041
1065
}
1042
1066
1067
+ static int prueth_hsr_port_link (struct net_device * ndev )
1068
+ {
1069
+ struct prueth_emac * emac = netdev_priv (ndev );
1070
+ struct prueth * prueth = emac -> prueth ;
1071
+ struct prueth_emac * emac0 ;
1072
+ struct prueth_emac * emac1 ;
1073
+
1074
+ emac0 = prueth -> emac [PRUETH_MAC0 ];
1075
+ emac1 = prueth -> emac [PRUETH_MAC1 ];
1076
+
1077
+ if (prueth -> is_switch_mode )
1078
+ return - EOPNOTSUPP ;
1079
+
1080
+ prueth -> hsr_members |= BIT (emac -> port_id );
1081
+ if (!prueth -> is_hsr_offload_mode ) {
1082
+ if (prueth -> hsr_members & BIT (PRUETH_PORT_MII0 ) &&
1083
+ prueth -> hsr_members & BIT (PRUETH_PORT_MII1 )) {
1084
+ if (!(emac0 -> ndev -> features &
1085
+ NETIF_PRUETH_HSR_OFFLOAD_FEATURES ) &&
1086
+ !(emac1 -> ndev -> features &
1087
+ NETIF_PRUETH_HSR_OFFLOAD_FEATURES ))
1088
+ return - EOPNOTSUPP ;
1089
+ prueth -> is_hsr_offload_mode = true;
1090
+ prueth -> default_vlan = 1 ;
1091
+ emac0 -> port_vlan = prueth -> default_vlan ;
1092
+ emac1 -> port_vlan = prueth -> default_vlan ;
1093
+ icssg_change_mode (prueth );
1094
+ netdev_dbg (ndev , "Enabling HSR offload mode\n" );
1095
+ }
1096
+ }
1097
+
1098
+ return 0 ;
1099
+ }
1100
+
1101
+ static void prueth_hsr_port_unlink (struct net_device * ndev )
1102
+ {
1103
+ struct prueth_emac * emac = netdev_priv (ndev );
1104
+ struct prueth * prueth = emac -> prueth ;
1105
+ struct prueth_emac * emac0 ;
1106
+ struct prueth_emac * emac1 ;
1107
+
1108
+ emac0 = prueth -> emac [PRUETH_MAC0 ];
1109
+ emac1 = prueth -> emac [PRUETH_MAC1 ];
1110
+
1111
+ prueth -> hsr_members &= ~BIT (emac -> port_id );
1112
+ if (prueth -> is_hsr_offload_mode ) {
1113
+ prueth -> is_hsr_offload_mode = false;
1114
+ emac0 -> port_vlan = 0 ;
1115
+ emac1 -> port_vlan = 0 ;
1116
+ prueth -> hsr_dev = NULL ;
1117
+ prueth_emac_restart (prueth );
1118
+ netdev_dbg (ndev , "Disabling HSR Offload mode\n" );
1119
+ }
1120
+ }
1121
+
1043
1122
/* netdev notifier */
1044
1123
static int prueth_netdevice_event (struct notifier_block * unused ,
1045
1124
unsigned long event , void * ptr )
1046
1125
{
1047
1126
struct netlink_ext_ack * extack = netdev_notifier_info_to_extack (ptr );
1048
1127
struct net_device * ndev = netdev_notifier_info_to_dev (ptr );
1049
1128
struct netdev_notifier_changeupper_info * info ;
1129
+ struct prueth_emac * emac = netdev_priv (ndev );
1130
+ struct prueth * prueth = emac -> prueth ;
1050
1131
int ret = NOTIFY_DONE ;
1051
1132
1052
1133
if (ndev -> netdev_ops != & emac_netdev_ops )
@@ -1056,6 +1137,25 @@ static int prueth_netdevice_event(struct notifier_block *unused,
1056
1137
case NETDEV_CHANGEUPPER :
1057
1138
info = ptr ;
1058
1139
1140
+ if ((ndev -> features & NETIF_PRUETH_HSR_OFFLOAD_FEATURES ) &&
1141
+ is_hsr_master (info -> upper_dev )) {
1142
+ if (info -> linking ) {
1143
+ if (!prueth -> hsr_dev ) {
1144
+ prueth -> hsr_dev = info -> upper_dev ;
1145
+ icssg_class_set_host_mac_addr (prueth -> miig_rt ,
1146
+ prueth -> hsr_dev -> dev_addr );
1147
+ } else {
1148
+ if (prueth -> hsr_dev != info -> upper_dev ) {
1149
+ netdev_dbg (ndev , "Both interfaces must be linked to same upper device\n" );
1150
+ return - EOPNOTSUPP ;
1151
+ }
1152
+ }
1153
+ prueth_hsr_port_link (ndev );
1154
+ } else {
1155
+ prueth_hsr_port_unlink (ndev );
1156
+ }
1157
+ }
1158
+
1059
1159
if (netif_is_bridge_master (info -> upper_dev )) {
1060
1160
if (info -> linking )
1061
1161
ret = prueth_netdevice_port_link (ndev , info -> upper_dev , extack );
0 commit comments