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_cpu_port(ds
, port
) || 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
);
138 for_each_set_bit(port
, group
, ds
->num_ports
)
139 ds
->ops
->port_mdb_add(ds
, port
, mdb
, trans
);
144 static int dsa_switch_mdb_del(struct dsa_switch
*ds
,
145 struct dsa_notifier_mdb_info
*info
)
147 const struct switchdev_obj_port_mdb
*mdb
= info
->mdb
;
149 if (!ds
->ops
->port_mdb_del
)
152 if (ds
->index
== info
->sw_index
)
153 return ds
->ops
->port_mdb_del(ds
, info
->port
, mdb
);
158 static int dsa_switch_vlan_add(struct dsa_switch
*ds
,
159 struct dsa_notifier_vlan_info
*info
)
161 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
162 struct switchdev_trans
*trans
= info
->trans
;
163 DECLARE_BITMAP(members
, ds
->num_ports
);
166 /* Build a mask of VLAN members */
167 bitmap_zero(members
, ds
->num_ports
);
168 if (ds
->index
== info
->sw_index
)
169 set_bit(info
->port
, members
);
170 for (port
= 0; port
< ds
->num_ports
; port
++)
171 if (dsa_is_cpu_port(ds
, port
) || dsa_is_dsa_port(ds
, port
))
172 set_bit(port
, members
);
174 if (switchdev_trans_ph_prepare(trans
)) {
175 if (!ds
->ops
->port_vlan_prepare
|| !ds
->ops
->port_vlan_add
)
178 for_each_set_bit(port
, members
, ds
->num_ports
) {
179 err
= ds
->ops
->port_vlan_prepare(ds
, port
, vlan
, trans
);
185 for_each_set_bit(port
, members
, ds
->num_ports
)
186 ds
->ops
->port_vlan_add(ds
, port
, vlan
, trans
);
191 static int dsa_switch_vlan_del(struct dsa_switch
*ds
,
192 struct dsa_notifier_vlan_info
*info
)
194 const struct switchdev_obj_port_vlan
*vlan
= info
->vlan
;
196 if (!ds
->ops
->port_vlan_del
)
199 if (ds
->index
== info
->sw_index
)
200 return ds
->ops
->port_vlan_del(ds
, info
->port
, vlan
);
205 static int dsa_switch_event(struct notifier_block
*nb
,
206 unsigned long event
, void *info
)
208 struct dsa_switch
*ds
= container_of(nb
, struct dsa_switch
, nb
);
212 case DSA_NOTIFIER_AGEING_TIME
:
213 err
= dsa_switch_ageing_time(ds
, info
);
215 case DSA_NOTIFIER_BRIDGE_JOIN
:
216 err
= dsa_switch_bridge_join(ds
, info
);
218 case DSA_NOTIFIER_BRIDGE_LEAVE
:
219 err
= dsa_switch_bridge_leave(ds
, info
);
221 case DSA_NOTIFIER_FDB_ADD
:
222 err
= dsa_switch_fdb_add(ds
, info
);
224 case DSA_NOTIFIER_FDB_DEL
:
225 err
= dsa_switch_fdb_del(ds
, info
);
227 case DSA_NOTIFIER_MDB_ADD
:
228 err
= dsa_switch_mdb_add(ds
, info
);
230 case DSA_NOTIFIER_MDB_DEL
:
231 err
= dsa_switch_mdb_del(ds
, info
);
233 case DSA_NOTIFIER_VLAN_ADD
:
234 err
= dsa_switch_vlan_add(ds
, info
);
236 case DSA_NOTIFIER_VLAN_DEL
:
237 err
= dsa_switch_vlan_del(ds
, info
);
244 /* Non-switchdev operations cannot be rolled back. If a DSA driver
245 * returns an error during the chained call, switch chips may be in an
246 * inconsistent state.
249 dev_dbg(ds
->dev
, "breaking chain for DSA event %lu (%d)\n",
252 return notifier_from_errno(err
);
255 int dsa_switch_register_notifier(struct dsa_switch
*ds
)
257 ds
->nb
.notifier_call
= dsa_switch_event
;
259 return raw_notifier_chain_register(&ds
->dst
->nh
, &ds
->nb
);
262 void dsa_switch_unregister_notifier(struct dsa_switch
*ds
)
266 err
= raw_notifier_chain_unregister(&ds
->dst
->nh
, &ds
->nb
);
268 dev_err(ds
->dev
, "failed to unregister notifier (%d)\n", err
);