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
;
139 DECLARE_BITMAP(group
, ds
->num_ports
);
142 /* Build a mask of Multicast group members */
143 bitmap_zero(group
, ds
->num_ports
);
144 if (ds
->index
== info
->sw_index
)
145 set_bit(info
->port
, group
);
146 for (port
= 0; port
< ds
->num_ports
; port
++)
147 if (dsa_is_dsa_port(ds
, port
))
148 set_bit(port
, group
);
150 if (switchdev_trans_ph_prepare(trans
))
151 return dsa_switch_mdb_prepare_bitmap(ds
, mdb
, group
);
153 dsa_switch_mdb_add_bitmap(ds
, mdb
, group
);
158 static int dsa_switch_mdb_del(struct dsa_switch
*ds
,
159 struct dsa_notifier_mdb_info
*info
)
161 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
163 if (!ds
->ops
->port_mdb_del
)
166 if (ds
->index
== info
->sw_index
)
167 return ds
->ops
->port_mdb_del(ds
, info
->port
, mdb
);
173 dsa_switch_vlan_prepare_bitmap(struct dsa_switch
*ds
,
174 const struct switchdev_obj_port_vlan
*vlan
,
175 const unsigned long *bitmap
)
179 if (!ds
->ops
->port_vlan_prepare
|| !ds
->ops
->port_vlan_add
)
182 for_each_set_bit(port
, bitmap
, ds
->num_ports
) {
183 err
= ds
->ops
->port_vlan_prepare(ds
, port
, vlan
);
192 dsa_switch_vlan_add_bitmap(struct dsa_switch
*ds
,
193 const struct switchdev_obj_port_vlan
*vlan
,
194 const unsigned long *bitmap
)
198 for_each_set_bit(port
, bitmap
, ds
->num_ports
)
199 ds
->ops
->port_vlan_add(ds
, port
, vlan
);
202 static int dsa_switch_vlan_add(struct dsa_switch
*ds
,
203 struct dsa_notifier_vlan_info
*info
)
205 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
206 struct switchdev_trans
*trans
= info
->trans
;
207 DECLARE_BITMAP(members
, ds
->num_ports
);
210 /* Build a mask of VLAN members */
211 bitmap_zero(members
, ds
->num_ports
);
212 if (ds
->index
== info
->sw_index
)
213 set_bit(info
->port
, members
);
214 for (port
= 0; port
< ds
->num_ports
; port
++)
215 if (dsa_is_cpu_port(ds
, port
) || dsa_is_dsa_port(ds
, port
))
216 set_bit(port
, members
);
218 if (switchdev_trans_ph_prepare(trans
))
219 return dsa_switch_vlan_prepare_bitmap(ds
, vlan
, members
);
221 dsa_switch_vlan_add_bitmap(ds
, vlan
, members
);
226 static int dsa_switch_vlan_del(struct dsa_switch
*ds
,
227 struct dsa_notifier_vlan_info
*info
)
229 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
231 if (!ds
->ops
->port_vlan_del
)
234 if (ds
->index
== info
->sw_index
)
235 return ds
->ops
->port_vlan_del(ds
, info
->port
, vlan
);
240 static int dsa_switch_event(struct notifier_block
*nb
,
241 unsigned long event
, void *info
)
243 struct dsa_switch
*ds
= container_of(nb
, struct dsa_switch
, nb
);
247 case DSA_NOTIFIER_AGEING_TIME
:
248 err
= dsa_switch_ageing_time(ds
, info
);
250 case DSA_NOTIFIER_BRIDGE_JOIN
:
251 err
= dsa_switch_bridge_join(ds
, info
);
253 case DSA_NOTIFIER_BRIDGE_LEAVE
:
254 err
= dsa_switch_bridge_leave(ds
, info
);
256 case DSA_NOTIFIER_FDB_ADD
:
257 err
= dsa_switch_fdb_add(ds
, info
);
259 case DSA_NOTIFIER_FDB_DEL
:
260 err
= dsa_switch_fdb_del(ds
, info
);
262 case DSA_NOTIFIER_MDB_ADD
:
263 err
= dsa_switch_mdb_add(ds
, info
);
265 case DSA_NOTIFIER_MDB_DEL
:
266 err
= dsa_switch_mdb_del(ds
, info
);
268 case DSA_NOTIFIER_VLAN_ADD
:
269 err
= dsa_switch_vlan_add(ds
, info
);
271 case DSA_NOTIFIER_VLAN_DEL
:
272 err
= dsa_switch_vlan_del(ds
, info
);
279 /* Non-switchdev operations cannot be rolled back. If a DSA driver
280 * returns an error during the chained call, switch chips may be in an
281 * inconsistent state.
284 dev_dbg(ds
->dev
, "breaking chain for DSA event %lu (%d)\n",
287 return notifier_from_errno(err
);
290 int dsa_switch_register_notifier(struct dsa_switch
*ds
)
292 ds
->nb
.notifier_call
= dsa_switch_event
;
294 return raw_notifier_chain_register(&ds
->dst
->nh
, &ds
->nb
);
297 void dsa_switch_unregister_notifier(struct dsa_switch
*ds
)
301 err
= raw_notifier_chain_unregister(&ds
->dst
->nh
, &ds
->nb
);
303 dev_err(ds
->dev
, "failed to unregister notifier (%d)\n", err
);