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 int port
= dsa_towards_port(ds
, info
->sw_index
, info
->port
);
88 if (!ds
->ops
->port_fdb_add
)
91 return ds
->ops
->port_fdb_add(ds
, port
, info
->addr
, info
->vid
);
94 static int dsa_switch_fdb_del(struct dsa_switch
*ds
,
95 struct dsa_notifier_fdb_info
*info
)
97 int port
= dsa_towards_port(ds
, info
->sw_index
, info
->port
);
99 if (!ds
->ops
->port_fdb_del
)
102 return ds
->ops
->port_fdb_del(ds
, port
, info
->addr
, info
->vid
);
106 dsa_switch_mdb_prepare_bitmap(struct dsa_switch
*ds
,
107 const struct switchdev_obj_port_mdb
*mdb
,
108 const unsigned long *bitmap
)
112 if (!ds
->ops
->port_mdb_prepare
|| !ds
->ops
->port_mdb_add
)
115 for_each_set_bit(port
, bitmap
, ds
->num_ports
) {
116 err
= ds
->ops
->port_mdb_prepare(ds
, port
, mdb
);
124 static void dsa_switch_mdb_add_bitmap(struct dsa_switch
*ds
,
125 const struct switchdev_obj_port_mdb
*mdb
,
126 const unsigned long *bitmap
)
130 for_each_set_bit(port
, bitmap
, ds
->num_ports
)
131 ds
->ops
->port_mdb_add(ds
, port
, mdb
);
134 static int dsa_switch_mdb_add(struct dsa_switch
*ds
,
135 struct dsa_notifier_mdb_info
*info
)
137 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
138 struct switchdev_trans
*trans
= info
->trans
;
141 /* Build a mask of Multicast group members */
142 bitmap_zero(ds
->bitmap
, ds
->num_ports
);
143 if (ds
->index
== info
->sw_index
)
144 set_bit(info
->port
, ds
->bitmap
);
145 for (port
= 0; port
< ds
->num_ports
; port
++)
146 if (dsa_is_dsa_port(ds
, port
))
147 set_bit(port
, ds
->bitmap
);
149 if (switchdev_trans_ph_prepare(trans
))
150 return dsa_switch_mdb_prepare_bitmap(ds
, mdb
, ds
->bitmap
);
152 dsa_switch_mdb_add_bitmap(ds
, mdb
, ds
->bitmap
);
157 static int dsa_switch_mdb_del(struct dsa_switch
*ds
,
158 struct dsa_notifier_mdb_info
*info
)
160 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
162 if (!ds
->ops
->port_mdb_del
)
165 if (ds
->index
== info
->sw_index
)
166 return ds
->ops
->port_mdb_del(ds
, info
->port
, mdb
);
172 dsa_switch_vlan_prepare_bitmap(struct dsa_switch
*ds
,
173 const struct switchdev_obj_port_vlan
*vlan
,
174 const unsigned long *bitmap
)
178 if (!ds
->ops
->port_vlan_prepare
|| !ds
->ops
->port_vlan_add
)
181 for_each_set_bit(port
, bitmap
, ds
->num_ports
) {
182 err
= ds
->ops
->port_vlan_prepare(ds
, port
, vlan
);
191 dsa_switch_vlan_add_bitmap(struct dsa_switch
*ds
,
192 const struct switchdev_obj_port_vlan
*vlan
,
193 const unsigned long *bitmap
)
197 for_each_set_bit(port
, bitmap
, ds
->num_ports
)
198 ds
->ops
->port_vlan_add(ds
, port
, vlan
);
201 static int dsa_switch_vlan_add(struct dsa_switch
*ds
,
202 struct dsa_notifier_vlan_info
*info
)
204 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
205 struct switchdev_trans
*trans
= info
->trans
;
208 /* Build a mask of VLAN members */
209 bitmap_zero(ds
->bitmap
, ds
->num_ports
);
210 if (ds
->index
== info
->sw_index
)
211 set_bit(info
->port
, ds
->bitmap
);
212 for (port
= 0; port
< ds
->num_ports
; port
++)
213 if (dsa_is_cpu_port(ds
, port
) || dsa_is_dsa_port(ds
, port
))
214 set_bit(port
, ds
->bitmap
);
216 if (switchdev_trans_ph_prepare(trans
))
217 return dsa_switch_vlan_prepare_bitmap(ds
, vlan
, ds
->bitmap
);
219 dsa_switch_vlan_add_bitmap(ds
, vlan
, ds
->bitmap
);
224 static int dsa_switch_vlan_del(struct dsa_switch
*ds
,
225 struct dsa_notifier_vlan_info
*info
)
227 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
229 if (!ds
->ops
->port_vlan_del
)
232 if (ds
->index
== info
->sw_index
)
233 return ds
->ops
->port_vlan_del(ds
, info
->port
, vlan
);
238 static int dsa_switch_event(struct notifier_block
*nb
,
239 unsigned long event
, void *info
)
241 struct dsa_switch
*ds
= container_of(nb
, struct dsa_switch
, nb
);
245 case DSA_NOTIFIER_AGEING_TIME
:
246 err
= dsa_switch_ageing_time(ds
, info
);
248 case DSA_NOTIFIER_BRIDGE_JOIN
:
249 err
= dsa_switch_bridge_join(ds
, info
);
251 case DSA_NOTIFIER_BRIDGE_LEAVE
:
252 err
= dsa_switch_bridge_leave(ds
, info
);
254 case DSA_NOTIFIER_FDB_ADD
:
255 err
= dsa_switch_fdb_add(ds
, info
);
257 case DSA_NOTIFIER_FDB_DEL
:
258 err
= dsa_switch_fdb_del(ds
, info
);
260 case DSA_NOTIFIER_MDB_ADD
:
261 err
= dsa_switch_mdb_add(ds
, info
);
263 case DSA_NOTIFIER_MDB_DEL
:
264 err
= dsa_switch_mdb_del(ds
, info
);
266 case DSA_NOTIFIER_VLAN_ADD
:
267 err
= dsa_switch_vlan_add(ds
, info
);
269 case DSA_NOTIFIER_VLAN_DEL
:
270 err
= dsa_switch_vlan_del(ds
, info
);
277 /* Non-switchdev operations cannot be rolled back. If a DSA driver
278 * returns an error during the chained call, switch chips may be in an
279 * inconsistent state.
282 dev_dbg(ds
->dev
, "breaking chain for DSA event %lu (%d)\n",
285 return notifier_from_errno(err
);
288 int dsa_switch_register_notifier(struct dsa_switch
*ds
)
290 ds
->nb
.notifier_call
= dsa_switch_event
;
292 return raw_notifier_chain_register(&ds
->dst
->nh
, &ds
->nb
);
295 void dsa_switch_unregister_notifier(struct dsa_switch
*ds
)
299 err
= raw_notifier_chain_unregister(&ds
->dst
->nh
, &ds
->nb
);
301 dev_err(ds
->dev
, "failed to unregister notifier (%d)\n", err
);