1313#include <linux/dma/ti-cppi5.h>
1414#include <linux/etherdevice.h>
1515#include <linux/genalloc.h>
16+ #include <linux/if_hsr.h>
1617#include <linux/if_vlan.h>
1718#include <linux/interrupt.h>
1819#include <linux/kernel.h>
4041#define DEFAULT_PORT_MASK 1
4142#define DEFAULT_UNTAG_MASK 1
4243
44+ #define NETIF_PRUETH_HSR_OFFLOAD_FEATURES NETIF_F_HW_HSR_FWD
45+
4346/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
4447#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
4548
@@ -118,6 +121,19 @@ static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)
118121 return IRQ_HANDLED ;
119122}
120123
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+
121137static struct icssg_firmwares icssg_switch_firmwares [] = {
122138 {
123139 .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)
152168
153169 if (prueth -> is_switch_mode )
154170 firmwares = icssg_switch_firmwares ;
171+ else if (prueth -> is_hsr_offload_mode )
172+ firmwares = icssg_hsr_firmwares ;
155173 else
156174 firmwares = icssg_emac_firmwares ;
157175
@@ -865,6 +883,7 @@ static int prueth_netdev_init(struct prueth *prueth,
865883 ndev -> ethtool_ops = & icssg_ethtool_ops ;
866884 ndev -> hw_features = NETIF_F_SG ;
867885 ndev -> features = ndev -> hw_features ;
886+ ndev -> hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES ;
868887
869888 netif_napi_add (ndev , & emac -> napi_rx , icssg_napi_rx_poll );
870889 hrtimer_init (& emac -> rx_hrtimer , CLOCK_MONOTONIC ,
@@ -953,7 +972,7 @@ static void prueth_emac_restart(struct prueth *prueth)
953972 netif_device_attach (emac1 -> ndev );
954973}
955974
956- static void icssg_enable_switch_mode (struct prueth * prueth )
975+ static void icssg_change_mode (struct prueth * prueth )
957976{
958977 struct prueth_emac * emac ;
959978 int mac ;
@@ -973,8 +992,13 @@ static void icssg_enable_switch_mode(struct prueth *prueth)
973992 BIT (emac -> port_id ) | DEFAULT_PORT_MASK ,
974993 BIT (emac -> port_id ) | DEFAULT_UNTAG_MASK ,
975994 true);
995+ if (prueth -> is_hsr_offload_mode )
996+ icssg_vtbl_modify (emac , DEFAULT_VID ,
997+ DEFAULT_PORT_MASK ,
998+ DEFAULT_UNTAG_MASK , true);
976999 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 );
9781002 }
9791003 }
9801004}
@@ -1012,7 +1036,7 @@ static int prueth_netdevice_port_link(struct net_device *ndev,
10121036 prueth -> is_switch_mode = true;
10131037 prueth -> default_vlan = 1 ;
10141038 emac -> port_vlan = prueth -> default_vlan ;
1015- icssg_enable_switch_mode (prueth );
1039+ icssg_change_mode (prueth );
10161040 }
10171041 }
10181042
@@ -1040,13 +1064,70 @@ static void prueth_netdevice_port_unlink(struct net_device *ndev)
10401064 prueth -> hw_bridge_dev = NULL ;
10411065}
10421066
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+
10431122/* netdev notifier */
10441123static int prueth_netdevice_event (struct notifier_block * unused ,
10451124 unsigned long event , void * ptr )
10461125{
10471126 struct netlink_ext_ack * extack = netdev_notifier_info_to_extack (ptr );
10481127 struct net_device * ndev = netdev_notifier_info_to_dev (ptr );
10491128 struct netdev_notifier_changeupper_info * info ;
1129+ struct prueth_emac * emac = netdev_priv (ndev );
1130+ struct prueth * prueth = emac -> prueth ;
10501131 int ret = NOTIFY_DONE ;
10511132
10521133 if (ndev -> netdev_ops != & emac_netdev_ops )
@@ -1056,6 +1137,25 @@ static int prueth_netdevice_event(struct notifier_block *unused,
10561137 case NETDEV_CHANGEUPPER :
10571138 info = ptr ;
10581139
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+
10591159 if (netif_is_bridge_master (info -> upper_dev )) {
10601160 if (info -> linking )
10611161 ret = prueth_netdevice_port_link (ndev , info -> upper_dev , extack );
0 commit comments