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