1 // SPDX-License-Identifier: GPL-2.0 2 /* Renesas Ethernet Switch device driver 3 * 4 * Copyright (C) 2025 - 2026 Renesas Electronics Corporation 5 */ 6 7 #include <linux/err.h> 8 #include <linux/etherdevice.h> 9 #include <linux/if_bridge.h> 10 #include <linux/kernel.h> 11 #include <net/switchdev.h> 12 13 #include "rswitch.h" 14 #include "rswitch_l2.h" 15 16 static bool rdev_for_l2_offload(struct rswitch_device *rdev) 17 { 18 return rdev->priv->offload_brdev && 19 rdev->brdev == rdev->priv->offload_brdev && 20 (test_bit(rdev->port, rdev->priv->opened_ports)); 21 } 22 23 static void rswitch_change_l2_hw_offloading(struct rswitch_device *rdev, 24 bool start, bool learning) 25 { 26 u32 bits = learning ? FWPC0_MACSSA | FWPC0_MACHLA | FWPC0_MACHMA : FWPC0_MACDSA; 27 u32 clear = start ? 0 : bits; 28 u32 set = start ? bits : 0; 29 30 if ((learning && rdev->learning_offloaded == start) || 31 (!learning && rdev->forwarding_offloaded == start)) 32 return; 33 34 rswitch_modify(rdev->priv->addr, FWPC0(rdev->port), clear, set); 35 36 if (learning) 37 rdev->learning_offloaded = start; 38 else 39 rdev->forwarding_offloaded = start; 40 41 netdev_info(rdev->ndev, "%s hw %s\n", start ? "starting" : "stopping", 42 learning ? "learning" : "forwarding"); 43 } 44 45 static void rswitch_update_l2_hw_learning(struct rswitch_private *priv) 46 { 47 struct rswitch_device *rdev; 48 bool learning_needed; 49 50 rswitch_for_all_ports(priv, rdev) { 51 if (rdev_for_l2_offload(rdev)) 52 learning_needed = rdev->learning_requested; 53 else 54 learning_needed = false; 55 56 rswitch_change_l2_hw_offloading(rdev, learning_needed, true); 57 } 58 } 59 60 static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) 61 { 62 struct rswitch_device *rdev; 63 bool new_forwarding_offload; 64 unsigned int fwd_mask; 65 66 /* calculate fwd_mask with zeroes in bits corresponding to ports that 67 * shall participate in hardware forwarding 68 */ 69 fwd_mask = GENMASK(RSWITCH_NUM_AGENTS - 1, 0); 70 71 rswitch_for_all_ports(priv, rdev) { 72 if (rdev_for_l2_offload(rdev) && rdev->forwarding_requested) 73 fwd_mask &= ~BIT(rdev->port); 74 } 75 76 rswitch_for_all_ports(priv, rdev) { 77 new_forwarding_offload = (rdev_for_l2_offload(rdev) && rdev->forwarding_requested); 78 79 if (new_forwarding_offload || rdev->forwarding_offloaded) { 80 /* Update allowed offload destinations even for ports 81 * with L2 offload enabled earlier. 82 * 83 * Do not allow L2 forwarding to self for hw port. 84 */ 85 iowrite32(FIELD_PREP(FWCP2_LTWFW_MASK, fwd_mask | BIT(rdev->port)), 86 priv->addr + FWPC2(rdev->port)); 87 } 88 89 if (new_forwarding_offload && !rdev->forwarding_offloaded) 90 rswitch_change_l2_hw_offloading(rdev, true, false); 91 else if (!new_forwarding_offload && rdev->forwarding_offloaded) 92 rswitch_change_l2_hw_offloading(rdev, false, false); 93 } 94 } 95 96 void rswitch_update_l2_offload(struct rswitch_private *priv) 97 { 98 rswitch_update_l2_hw_learning(priv); 99 rswitch_update_l2_hw_forwarding(priv); 100 } 101 102 static void rswitch_update_offload_brdev(struct rswitch_private *priv) 103 { 104 struct net_device *offload_brdev = NULL; 105 struct rswitch_device *rdev, *rdev2; 106 107 rswitch_for_all_ports(priv, rdev) { 108 if (!rdev->brdev) 109 continue; 110 rswitch_for_all_ports(priv, rdev2) { 111 if (rdev2 == rdev) 112 break; 113 if (rdev2->brdev == rdev->brdev) { 114 offload_brdev = rdev->brdev; 115 break; 116 } 117 } 118 if (offload_brdev) 119 break; 120 } 121 122 if (offload_brdev == priv->offload_brdev) 123 dev_dbg(&priv->pdev->dev, 124 "changing l2 offload from %s to %s\n", 125 netdev_name(priv->offload_brdev), 126 netdev_name(offload_brdev)); 127 else if (offload_brdev) 128 dev_dbg(&priv->pdev->dev, "starting l2 offload for %s\n", 129 netdev_name(offload_brdev)); 130 else if (!offload_brdev) 131 dev_dbg(&priv->pdev->dev, "stopping l2 offload for %s\n", 132 netdev_name(priv->offload_brdev)); 133 134 priv->offload_brdev = offload_brdev; 135 136 rswitch_update_l2_offload(priv); 137 } 138 139 static bool rswitch_port_check(const struct net_device *ndev) 140 { 141 return is_rdev(ndev); 142 } 143 144 static void rswitch_port_update_brdev(struct net_device *ndev, 145 struct net_device *brdev) 146 { 147 struct rswitch_device *rdev; 148 149 if (!is_rdev(ndev)) 150 return; 151 152 rdev = netdev_priv(ndev); 153 rdev->brdev = brdev; 154 rswitch_update_offload_brdev(rdev->priv); 155 } 156 157 static int rswitch_port_update_stp_state(struct net_device *ndev, u8 stp_state) 158 { 159 struct rswitch_device *rdev; 160 161 if (!is_rdev(ndev)) 162 return -ENODEV; 163 164 rdev = netdev_priv(ndev); 165 rdev->learning_requested = (stp_state == BR_STATE_LEARNING || 166 stp_state == BR_STATE_FORWARDING); 167 rdev->forwarding_requested = (stp_state == BR_STATE_FORWARDING); 168 rswitch_update_l2_offload(rdev->priv); 169 170 return 0; 171 } 172 173 static int rswitch_netdevice_event(struct notifier_block *nb, 174 unsigned long event, void *ptr) 175 { 176 struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 177 struct netdev_notifier_changeupper_info *info; 178 struct net_device *brdev; 179 180 if (!rswitch_port_check(ndev)) 181 return NOTIFY_DONE; 182 if (event != NETDEV_CHANGEUPPER) 183 return NOTIFY_DONE; 184 185 info = ptr; 186 187 if (netif_is_bridge_master(info->upper_dev)) { 188 brdev = info->linking ? info->upper_dev : NULL; 189 rswitch_port_update_brdev(ndev, brdev); 190 } 191 192 return NOTIFY_OK; 193 } 194 195 static int rswitch_update_ageing_time(struct net_device *ndev, clock_t time) 196 { 197 struct rswitch_device *rdev = netdev_priv(ndev); 198 u32 reg_val; 199 200 if (!is_rdev(ndev)) 201 return -ENODEV; 202 203 if (!FIELD_FIT(FWMACAGC_MACAGT, time)) 204 return -EINVAL; 205 206 reg_val = FIELD_PREP(FWMACAGC_MACAGT, time); 207 reg_val |= FWMACAGC_MACAGE | FWMACAGC_MACAGSL; 208 iowrite32(reg_val, rdev->priv->addr + FWMACAGC); 209 210 return 0; 211 } 212 213 static int rswitch_port_attr_set(struct net_device *ndev, const void *ctx, 214 const struct switchdev_attr *attr, 215 struct netlink_ext_ack *extack) 216 { 217 switch (attr->id) { 218 case SWITCHDEV_ATTR_ID_PORT_STP_STATE: 219 return rswitch_port_update_stp_state(ndev, attr->u.stp_state); 220 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: 221 return rswitch_update_ageing_time(ndev, attr->u.ageing_time); 222 default: 223 return -EOPNOTSUPP; 224 } 225 } 226 227 static int rswitch_switchdev_event(struct notifier_block *nb, 228 unsigned long event, void *ptr) 229 { 230 struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); 231 int ret; 232 233 if (event == SWITCHDEV_PORT_ATTR_SET) { 234 ret = switchdev_handle_port_attr_set(ndev, ptr, 235 rswitch_port_check, 236 rswitch_port_attr_set); 237 return notifier_from_errno(ret); 238 } 239 240 if (!rswitch_port_check(ndev)) 241 return NOTIFY_DONE; 242 243 return notifier_from_errno(-EOPNOTSUPP); 244 } 245 246 static int rswitch_switchdev_blocking_event(struct notifier_block *nb, 247 unsigned long event, void *ptr) 248 { 249 struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); 250 int ret; 251 252 switch (event) { 253 case SWITCHDEV_PORT_OBJ_ADD: 254 return -EOPNOTSUPP; 255 case SWITCHDEV_PORT_OBJ_DEL: 256 return -EOPNOTSUPP; 257 case SWITCHDEV_PORT_ATTR_SET: 258 ret = switchdev_handle_port_attr_set(ndev, ptr, 259 rswitch_port_check, 260 rswitch_port_attr_set); 261 break; 262 default: 263 if (!rswitch_port_check(ndev)) 264 return NOTIFY_DONE; 265 ret = -EOPNOTSUPP; 266 } 267 268 return notifier_from_errno(ret); 269 } 270 271 static struct notifier_block rswitch_netdevice_nb = { 272 .notifier_call = rswitch_netdevice_event, 273 }; 274 275 static struct notifier_block rswitch_switchdev_nb = { 276 .notifier_call = rswitch_switchdev_event, 277 }; 278 279 static struct notifier_block rswitch_switchdev_blocking_nb = { 280 .notifier_call = rswitch_switchdev_blocking_event, 281 }; 282 283 int rswitch_register_notifiers(void) 284 { 285 int ret; 286 287 ret = register_netdevice_notifier(&rswitch_netdevice_nb); 288 if (ret) 289 goto register_netdevice_notifier_failed; 290 291 ret = register_switchdev_notifier(&rswitch_switchdev_nb); 292 if (ret) 293 goto register_switchdev_notifier_failed; 294 295 ret = register_switchdev_blocking_notifier(&rswitch_switchdev_blocking_nb); 296 if (ret) 297 goto register_switchdev_blocking_notifier_failed; 298 299 return 0; 300 301 register_switchdev_blocking_notifier_failed: 302 unregister_switchdev_notifier(&rswitch_switchdev_nb); 303 register_switchdev_notifier_failed: 304 unregister_netdevice_notifier(&rswitch_netdevice_nb); 305 register_netdevice_notifier_failed: 306 307 return ret; 308 } 309 310 void rswitch_unregister_notifiers(void) 311 { 312 unregister_switchdev_blocking_notifier(&rswitch_switchdev_blocking_nb); 313 unregister_switchdev_notifier(&rswitch_switchdev_nb); 314 unregister_netdevice_notifier(&rswitch_netdevice_nb); 315 } 316