2 * Handling of a single switch chip, part of a switch fabric
4 * Copyright (c) 2017 Savoir-faire Linux Inc.
5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
13 #include <linux/netdevice.h>
14 #include <linux/notifier.h>
15 #include <net/switchdev.h>
19 static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch
*ds
,
20 unsigned int ageing_time
)
24 for (i
= 0; i
< ds
->num_ports
; ++i
) {
25 struct dsa_port
*dp
= &ds
->ports
[i
];
27 if (dp
->ageing_time
&& dp
->ageing_time
< ageing_time
)
28 ageing_time
= dp
->ageing_time
;
34 static int dsa_switch_ageing_time(struct dsa_switch
*ds
,
35 struct dsa_notifier_ageing_time_info
*info
)
37 unsigned int ageing_time
= info
->ageing_time
;
38 struct switchdev_trans
*trans
= info
->trans
;
40 if (switchdev_trans_ph_prepare(trans
)) {
41 if (ds
->ageing_time_min
&& ageing_time
< ds
->ageing_time_min
)
43 if (ds
->ageing_time_max
&& ageing_time
> ds
->ageing_time_max
)
48 /* Program the fastest ageing time in case of multiple bridges */
49 ageing_time
= dsa_switch_fastest_ageing_time(ds
, ageing_time
);
51 if (ds
->ops
->set_ageing_time
)
52 return ds
->ops
->set_ageing_time(ds
, ageing_time
);
57 static int dsa_switch_bridge_join(struct dsa_switch
*ds
,
58 struct dsa_notifier_bridge_info
*info
)
60 if (ds
->index
== info
->sw_index
&& ds
->ops
->port_bridge_join
)
61 return ds
->ops
->port_bridge_join(ds
, info
->port
, info
->br
);
63 if (ds
->index
!= info
->sw_index
&& ds
->ops
->crosschip_bridge_join
)
64 return ds
->ops
->crosschip_bridge_join(ds
, info
->sw_index
,
65 info
->port
, info
->br
);
70 static int dsa_switch_bridge_leave(struct dsa_switch
*ds
,
71 struct dsa_notifier_bridge_info
*info
)
73 if (ds
->index
== info
->sw_index
&& ds
->ops
->port_bridge_leave
)
74 ds
->ops
->port_bridge_leave(ds
, info
->port
, info
->br
);
76 if (ds
->index
!= info
->sw_index
&& ds
->ops
->crosschip_bridge_leave
)
77 ds
->ops
->crosschip_bridge_leave(ds
, info
->sw_index
, info
->port
,
83 static int dsa_switch_fdb_add(struct dsa_switch
*ds
,
84 struct dsa_notifier_fdb_info
*info
)
86 /* Do not care yet about other switch chips of the fabric */
87 if (ds
->index
!= info
->sw_index
)
90 if (!ds
->ops
->port_fdb_add
)
93 return ds
->ops
->port_fdb_add(ds
, info
->port
, info
->addr
,
97 static int dsa_switch_fdb_del(struct dsa_switch
*ds
,
98 struct dsa_notifier_fdb_info
*info
)
100 /* Do not care yet about other switch chips of the fabric */
101 if (ds
->index
!= info
->sw_index
)
104 if (!ds
->ops
->port_fdb_del
)
107 return ds
->ops
->port_fdb_del(ds
, info
->port
, info
->addr
,
111 static int dsa_switch_mdb_add(struct dsa_switch
*ds
,
112 struct dsa_notifier_mdb_info
*info
)
114 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
115 struct switchdev_trans
*trans
= info
->trans
;
116 DECLARE_BITMAP(group
, ds
->num_ports
);
119 /* Build a mask of Multicast group members */
120 bitmap_zero(group
, ds
->num_ports
);
121 if (ds
->index
== info
->sw_index
)
122 set_bit(info
->port
, group
);
123 for (port
= 0; port
< ds
->num_ports
; port
++)
124 if (dsa_is_dsa_port(ds
, port
))
125 set_bit(port
, group
);
127 if (switchdev_trans_ph_prepare(trans
)) {
128 if (!ds
->ops
->port_mdb_prepare
|| !ds
->ops
->port_mdb_add
)
131 for_each_set_bit(port
, group
, ds
->num_ports
) {
132 err
= ds
->ops
->port_mdb_prepare(ds
, port
, mdb
, trans
);
140 for_each_set_bit(port
, group
, ds
->num_ports
)
141 ds
->ops
->port_mdb_add(ds
, port
, mdb
, trans
);
146 static int dsa_switch_mdb_del(struct dsa_switch
*ds
,
147 struct dsa_notifier_mdb_info
*info
)
149 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
151 if (!ds
->ops
->port_mdb_del
)
154 if (ds
->index
== info
->sw_index
)
155 return ds
->ops
->port_mdb_del(ds
, info
->port
, mdb
);
160 static int dsa_switch_vlan_add(struct dsa_switch
*ds
,
161 struct dsa_notifier_vlan_info
*info
)
163 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
164 struct switchdev_trans
*trans
= info
->trans
;
165 DECLARE_BITMAP(members
, ds
->num_ports
);
168 /* Build a mask of VLAN members */
169 bitmap_zero(members
, ds
->num_ports
);
170 if (ds
->index
== info
->sw_index
)
171 set_bit(info
->port
, members
);
172 for (port
= 0; port
< ds
->num_ports
; port
++)
173 if (dsa_is_cpu_port(ds
, port
) || dsa_is_dsa_port(ds
, port
))
174 set_bit(port
, members
);
176 if (switchdev_trans_ph_prepare(trans
)) {
177 if (!ds
->ops
->port_vlan_prepare
|| !ds
->ops
->port_vlan_add
)
180 for_each_set_bit(port
, members
, ds
->num_ports
) {
181 err
= ds
->ops
->port_vlan_prepare(ds
, port
, vlan
, trans
);
189 for_each_set_bit(port
, members
, ds
->num_ports
)
190 ds
->ops
->port_vlan_add(ds
, port
, vlan
, trans
);
195 static int dsa_switch_vlan_del(struct dsa_switch
*ds
,
196 struct dsa_notifier_vlan_info
*info
)
198 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
200 if (!ds
->ops
->port_vlan_del
)
203 if (ds
->index
== info
->sw_index
)
204 return ds
->ops
->port_vlan_del(ds
, info
->port
, vlan
);
209 static int dsa_switch_event(struct notifier_block
*nb
,
210 unsigned long event
, void *info
)
212 struct dsa_switch
*ds
= container_of(nb
, struct dsa_switch
, nb
);
216 case DSA_NOTIFIER_AGEING_TIME
:
217 err
= dsa_switch_ageing_time(ds
, info
);
219 case DSA_NOTIFIER_BRIDGE_JOIN
:
220 err
= dsa_switch_bridge_join(ds
, info
);
222 case DSA_NOTIFIER_BRIDGE_LEAVE
:
223 err
= dsa_switch_bridge_leave(ds
, info
);
225 case DSA_NOTIFIER_FDB_ADD
:
226 err
= dsa_switch_fdb_add(ds
, info
);
228 case DSA_NOTIFIER_FDB_DEL
:
229 err
= dsa_switch_fdb_del(ds
, info
);
231 case DSA_NOTIFIER_MDB_ADD
:
232 err
= dsa_switch_mdb_add(ds
, info
);
234 case DSA_NOTIFIER_MDB_DEL
:
235 err
= dsa_switch_mdb_del(ds
, info
);
237 case DSA_NOTIFIER_VLAN_ADD
:
238 err
= dsa_switch_vlan_add(ds
, info
);
240 case DSA_NOTIFIER_VLAN_DEL
:
241 err
= dsa_switch_vlan_del(ds
, info
);
248 /* Non-switchdev operations cannot be rolled back. If a DSA driver
249 * returns an error during the chained call, switch chips may be in an
250 * inconsistent state.
253 dev_dbg(ds
->dev
, "breaking chain for DSA event %lu (%d)\n",
256 return notifier_from_errno(err
);
259 int dsa_switch_register_notifier(struct dsa_switch
*ds
)
261 ds
->nb
.notifier_call
= dsa_switch_event
;
263 return raw_notifier_chain_register(&ds
->dst
->nh
, &ds
->nb
);
266 void dsa_switch_unregister_notifier(struct dsa_switch
*ds
)
270 err
= raw_notifier_chain_unregister(&ds
->dst
->nh
, &ds
->nb
);
272 dev_err(ds
->dev
, "failed to unregister notifier (%d)\n", err
);