1 // SPDX-License-Identifier: GPL-2.0
3 /* Texas Instruments K3 ICSSG Ethernet Switchdev Driver
5 * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
9 #include <linux/etherdevice.h>
10 #include <linux/if_bridge.h>
11 #include <linux/netdevice.h>
12 #include <linux/workqueue.h>
13 #include <net/switchdev.h>
15 #include "icssg_prueth.h"
16 #include "icssg_switchdev.h"
17 #include "icssg_mii_rt.h"
19 struct prueth_switchdev_event_work
{
20 struct work_struct work
;
21 struct switchdev_notifier_fdb_info fdb_info
;
22 struct prueth_emac
*emac
;
26 static int prueth_switchdev_stp_state_set(struct prueth_emac
*emac
,
29 enum icssg_port_state_cmd emac_state
;
33 case BR_STATE_FORWARDING
:
34 emac_state
= ICSSG_EMAC_PORT_FORWARD
;
36 case BR_STATE_DISABLED
:
37 emac_state
= ICSSG_EMAC_PORT_DISABLE
;
39 case BR_STATE_LISTENING
:
40 case BR_STATE_BLOCKING
:
41 emac_state
= ICSSG_EMAC_PORT_BLOCK
;
47 icssg_set_port_state(emac
, emac_state
);
48 netdev_dbg(emac
->ndev
, "STP state: %u\n", emac_state
);
53 static int prueth_switchdev_attr_br_flags_set(struct prueth_emac
*emac
,
54 struct net_device
*orig_dev
,
55 struct switchdev_brport_flags brport_flags
)
57 enum icssg_port_state_cmd emac_state
;
59 if (brport_flags
.mask
& BR_MCAST_FLOOD
)
60 emac_state
= ICSSG_EMAC_PORT_MC_FLOODING_ENABLE
;
62 emac_state
= ICSSG_EMAC_PORT_MC_FLOODING_DISABLE
;
64 netdev_dbg(emac
->ndev
, "BR_MCAST_FLOOD: %d port %u\n",
65 emac_state
, emac
->port_id
);
67 icssg_set_port_state(emac
, emac_state
);
72 static int prueth_switchdev_attr_br_flags_pre_set(struct net_device
*netdev
,
73 struct switchdev_brport_flags brport_flags
)
75 if (brport_flags
.mask
& ~(BR_LEARNING
| BR_MCAST_FLOOD
))
81 static int prueth_switchdev_attr_set(struct net_device
*ndev
, const void *ctx
,
82 const struct switchdev_attr
*attr
,
83 struct netlink_ext_ack
*extack
)
85 struct prueth_emac
*emac
= netdev_priv(ndev
);
88 netdev_dbg(ndev
, "attr: id %u port: %u\n", attr
->id
, emac
->port_id
);
91 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
:
92 ret
= prueth_switchdev_attr_br_flags_pre_set(ndev
,
93 attr
->u
.brport_flags
);
95 case SWITCHDEV_ATTR_ID_PORT_STP_STATE
:
96 ret
= prueth_switchdev_stp_state_set(emac
,
98 netdev_dbg(ndev
, "stp state: %u\n", attr
->u
.stp_state
);
100 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS
:
101 ret
= prueth_switchdev_attr_br_flags_set(emac
, attr
->orig_dev
,
102 attr
->u
.brport_flags
);
112 static void prueth_switchdev_fdb_offload_notify(struct net_device
*ndev
,
113 struct switchdev_notifier_fdb_info
*rcv
)
115 struct switchdev_notifier_fdb_info info
;
117 memset(&info
, 0, sizeof(info
));
118 info
.addr
= rcv
->addr
;
120 info
.offloaded
= true;
121 call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED
,
122 ndev
, &info
.info
, NULL
);
125 static void prueth_switchdev_event_work(struct work_struct
*work
)
127 struct prueth_switchdev_event_work
*switchdev_work
=
128 container_of(work
, struct prueth_switchdev_event_work
, work
);
129 struct prueth_emac
*emac
= switchdev_work
->emac
;
130 struct switchdev_notifier_fdb_info
*fdb
;
131 int port_id
= emac
->port_id
;
135 switch (switchdev_work
->event
) {
136 case SWITCHDEV_FDB_ADD_TO_DEVICE
:
137 fdb
= &switchdev_work
->fdb_info
;
139 netdev_dbg(emac
->ndev
, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
140 fdb
->addr
, fdb
->vid
, fdb
->added_by_user
,
141 fdb
->offloaded
, port_id
);
143 if (!fdb
->added_by_user
)
145 if (!ether_addr_equal(emac
->mac_addr
, fdb
->addr
))
148 ret
= icssg_fdb_add_del(emac
, fdb
->addr
, fdb
->vid
,
151 prueth_switchdev_fdb_offload_notify(emac
->ndev
, fdb
);
153 case SWITCHDEV_FDB_DEL_TO_DEVICE
:
154 fdb
= &switchdev_work
->fdb_info
;
156 netdev_dbg(emac
->ndev
, "prueth_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n",
157 fdb
->addr
, fdb
->vid
, fdb
->added_by_user
,
158 fdb
->offloaded
, port_id
);
160 if (!fdb
->added_by_user
)
162 if (!ether_addr_equal(emac
->mac_addr
, fdb
->addr
))
164 icssg_fdb_add_del(emac
, fdb
->addr
, fdb
->vid
,
165 BIT(port_id
), false);
172 kfree(switchdev_work
->fdb_info
.addr
);
173 kfree(switchdev_work
);
177 static int prueth_switchdev_event(struct notifier_block
*unused
,
178 unsigned long event
, void *ptr
)
180 struct net_device
*ndev
= switchdev_notifier_info_to_dev(ptr
);
181 struct prueth_switchdev_event_work
*switchdev_work
;
182 struct switchdev_notifier_fdb_info
*fdb_info
= ptr
;
183 struct prueth_emac
*emac
= netdev_priv(ndev
);
186 if (!prueth_dev_check(ndev
))
189 if (event
== SWITCHDEV_PORT_ATTR_SET
) {
190 err
= switchdev_handle_port_attr_set(ndev
, ptr
,
192 prueth_switchdev_attr_set
);
193 return notifier_from_errno(err
);
196 switchdev_work
= kzalloc(sizeof(*switchdev_work
), GFP_ATOMIC
);
197 if (WARN_ON(!switchdev_work
))
200 INIT_WORK(&switchdev_work
->work
, prueth_switchdev_event_work
);
201 switchdev_work
->emac
= emac
;
202 switchdev_work
->event
= event
;
205 case SWITCHDEV_FDB_ADD_TO_DEVICE
:
206 case SWITCHDEV_FDB_DEL_TO_DEVICE
:
207 memcpy(&switchdev_work
->fdb_info
, ptr
,
208 sizeof(switchdev_work
->fdb_info
));
209 switchdev_work
->fdb_info
.addr
= kzalloc(ETH_ALEN
, GFP_ATOMIC
);
210 if (!switchdev_work
->fdb_info
.addr
)
212 ether_addr_copy((u8
*)switchdev_work
->fdb_info
.addr
,
217 kfree(switchdev_work
);
221 queue_work(system_long_wq
, &switchdev_work
->work
);
226 kfree(switchdev_work
);
230 static int prueth_switchdev_vlan_add(struct prueth_emac
*emac
, bool untag
, bool pvid
,
231 u8 vid
, struct net_device
*orig_dev
)
233 bool cpu_port
= netif_is_bridge_master(orig_dev
);
239 port_mask
= BIT(PRUETH_PORT_HOST
);
241 port_mask
= BIT(emac
->port_id
);
244 untag_mask
= port_mask
;
246 icssg_vtbl_modify(emac
, vid
, port_mask
, untag_mask
, true);
248 netdev_dbg(emac
->ndev
, "VID add vid:%u port_mask:%X untag_mask %X PVID %d\n",
249 vid
, port_mask
, untag_mask
, pvid
);
254 icssg_set_pvid(emac
->prueth
, vid
, emac
->port_id
);
259 static int prueth_switchdev_vlan_del(struct prueth_emac
*emac
, u16 vid
,
260 struct net_device
*orig_dev
)
262 bool cpu_port
= netif_is_bridge_master(orig_dev
);
267 port_mask
= BIT(PRUETH_PORT_HOST
);
269 port_mask
= BIT(emac
->port_id
);
271 icssg_vtbl_modify(emac
, vid
, port_mask
, 0, false);
274 icssg_fdb_add_del(emac
, emac
->mac_addr
, vid
,
275 BIT(PRUETH_PORT_HOST
), false);
277 if (vid
== icssg_get_pvid(emac
))
278 icssg_set_pvid(emac
->prueth
, 0, emac
->port_id
);
280 netdev_dbg(emac
->ndev
, "VID del vid:%u port_mask:%X\n",
286 static int prueth_switchdev_vlans_add(struct prueth_emac
*emac
,
287 const struct switchdev_obj_port_vlan
*vlan
)
289 bool untag
= vlan
->flags
& BRIDGE_VLAN_INFO_UNTAGGED
;
290 struct net_device
*orig_dev
= vlan
->obj
.orig_dev
;
291 bool cpu_port
= netif_is_bridge_master(orig_dev
);
292 bool pvid
= vlan
->flags
& BRIDGE_VLAN_INFO_PVID
;
294 netdev_dbg(emac
->ndev
, "VID add vid:%u flags:%X\n",
295 vlan
->vid
, vlan
->flags
);
297 if (cpu_port
&& !(vlan
->flags
& BRIDGE_VLAN_INFO_BRENTRY
))
300 if (vlan
->vid
> 0xff)
303 return prueth_switchdev_vlan_add(emac
, untag
, pvid
, vlan
->vid
,
307 static int prueth_switchdev_vlans_del(struct prueth_emac
*emac
,
308 const struct switchdev_obj_port_vlan
*vlan
)
310 if (vlan
->vid
> 0xff)
313 return prueth_switchdev_vlan_del(emac
, vlan
->vid
,
317 static int prueth_switchdev_mdb_add(struct prueth_emac
*emac
,
318 struct switchdev_obj_port_mdb
*mdb
)
320 struct net_device
*orig_dev
= mdb
->obj
.orig_dev
;
321 u8 port_mask
, fid_c2
;
325 cpu_port
= netif_is_bridge_master(orig_dev
);
328 port_mask
= BIT(PRUETH_PORT_HOST
);
330 port_mask
= BIT(emac
->port_id
);
332 fid_c2
= icssg_fdb_lookup(emac
, mdb
->addr
, mdb
->vid
);
334 err
= icssg_fdb_add_del(emac
, mdb
->addr
, mdb
->vid
, fid_c2
| port_mask
, true);
335 netdev_dbg(emac
->ndev
, "MDB add vid %u:%pM ports: %X\n",
336 mdb
->vid
, mdb
->addr
, port_mask
);
341 static int prueth_switchdev_mdb_del(struct prueth_emac
*emac
,
342 struct switchdev_obj_port_mdb
*mdb
)
344 struct net_device
*orig_dev
= mdb
->obj
.orig_dev
;
345 int del_mask
, ret
, fid_c2
;
348 cpu_port
= netif_is_bridge_master(orig_dev
);
351 del_mask
= BIT(PRUETH_PORT_HOST
);
353 del_mask
= BIT(emac
->port_id
);
355 fid_c2
= icssg_fdb_lookup(emac
, mdb
->addr
, mdb
->vid
);
357 if (fid_c2
& ~del_mask
)
358 ret
= icssg_fdb_add_del(emac
, mdb
->addr
, mdb
->vid
, fid_c2
& ~del_mask
, true);
360 ret
= icssg_fdb_add_del(emac
, mdb
->addr
, mdb
->vid
, 0, false);
362 netdev_dbg(emac
->ndev
, "MDB del vid %u:%pM ports: %X\n",
363 mdb
->vid
, mdb
->addr
, del_mask
);
368 static int prueth_switchdev_obj_add(struct net_device
*ndev
, const void *ctx
,
369 const struct switchdev_obj
*obj
,
370 struct netlink_ext_ack
*extack
)
372 struct switchdev_obj_port_vlan
*vlan
= SWITCHDEV_OBJ_PORT_VLAN(obj
);
373 struct switchdev_obj_port_mdb
*mdb
= SWITCHDEV_OBJ_PORT_MDB(obj
);
374 struct prueth_emac
*emac
= netdev_priv(ndev
);
377 netdev_dbg(ndev
, "obj_add: id %u port: %u\n", obj
->id
, emac
->port_id
);
380 case SWITCHDEV_OBJ_ID_PORT_VLAN
:
381 err
= prueth_switchdev_vlans_add(emac
, vlan
);
383 case SWITCHDEV_OBJ_ID_PORT_MDB
:
384 case SWITCHDEV_OBJ_ID_HOST_MDB
:
385 err
= prueth_switchdev_mdb_add(emac
, mdb
);
395 static int prueth_switchdev_obj_del(struct net_device
*ndev
, const void *ctx
,
396 const struct switchdev_obj
*obj
)
398 struct switchdev_obj_port_vlan
*vlan
= SWITCHDEV_OBJ_PORT_VLAN(obj
);
399 struct switchdev_obj_port_mdb
*mdb
= SWITCHDEV_OBJ_PORT_MDB(obj
);
400 struct prueth_emac
*emac
= netdev_priv(ndev
);
403 netdev_dbg(ndev
, "obj_del: id %u port: %u\n", obj
->id
, emac
->port_id
);
406 case SWITCHDEV_OBJ_ID_PORT_VLAN
:
407 err
= prueth_switchdev_vlans_del(emac
, vlan
);
409 case SWITCHDEV_OBJ_ID_PORT_MDB
:
410 case SWITCHDEV_OBJ_ID_HOST_MDB
:
411 err
= prueth_switchdev_mdb_del(emac
, mdb
);
421 static int prueth_switchdev_blocking_event(struct notifier_block
*unused
,
422 unsigned long event
, void *ptr
)
424 struct net_device
*dev
= switchdev_notifier_info_to_dev(ptr
);
428 case SWITCHDEV_PORT_OBJ_ADD
:
429 err
= switchdev_handle_port_obj_add(dev
, ptr
,
431 prueth_switchdev_obj_add
);
432 return notifier_from_errno(err
);
433 case SWITCHDEV_PORT_OBJ_DEL
:
434 err
= switchdev_handle_port_obj_del(dev
, ptr
,
436 prueth_switchdev_obj_del
);
437 return notifier_from_errno(err
);
438 case SWITCHDEV_PORT_ATTR_SET
:
439 err
= switchdev_handle_port_attr_set(dev
, ptr
,
441 prueth_switchdev_attr_set
);
442 return notifier_from_errno(err
);
450 int prueth_switchdev_register_notifiers(struct prueth
*prueth
)
454 prueth
->prueth_switchdev_nb
.notifier_call
= &prueth_switchdev_event
;
455 ret
= register_switchdev_notifier(&prueth
->prueth_switchdev_nb
);
457 dev_err(prueth
->dev
, "register switchdev notifier fail ret:%d\n",
462 prueth
->prueth_switchdev_bl_nb
.notifier_call
= &prueth_switchdev_blocking_event
;
463 ret
= register_switchdev_blocking_notifier(&prueth
->prueth_switchdev_bl_nb
);
465 dev_err(prueth
->dev
, "register switchdev blocking notifier ret:%d\n",
467 unregister_switchdev_notifier(&prueth
->prueth_switchdev_nb
);
473 void prueth_switchdev_unregister_notifiers(struct prueth
*prueth
)
475 unregister_switchdev_blocking_notifier(&prueth
->prueth_switchdev_bl_nb
);
476 unregister_switchdev_notifier(&prueth
->prueth_switchdev_nb
);