summaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c108
1 files changed, 43 insertions, 65 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 23b4e5b347dc..007b8f40df06 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -250,75 +250,12 @@ done:
250 return err; 250 return err;
251} 251}
252 252
253struct switchdev_attr_set_work { 253static int switchdev_port_attr_set_now(struct net_device *dev,
254 struct work_struct work; 254 const struct switchdev_attr *attr)
255 struct net_device *dev;
256 struct switchdev_attr attr;
257};
258
259static void switchdev_port_attr_set_work(struct work_struct *work)
260{
261 struct switchdev_attr_set_work *asw =
262 container_of(work, struct switchdev_attr_set_work, work);
263 int err;
264
265 rtnl_lock();
266 err = switchdev_port_attr_set(asw->dev, &asw->attr);
267 if (err && err != -EOPNOTSUPP)
268 netdev_err(asw->dev, "failed (err=%d) to set attribute (id=%d)\n",
269 err, asw->attr.id);
270 rtnl_unlock();
271
272 dev_put(asw->dev);
273 kfree(work);
274}
275
276static int switchdev_port_attr_set_defer(struct net_device *dev,
277 const struct switchdev_attr *attr)
278{
279 struct switchdev_attr_set_work *asw;
280
281 asw = kmalloc(sizeof(*asw), GFP_ATOMIC);
282 if (!asw)
283 return -ENOMEM;
284
285 INIT_WORK(&asw->work, switchdev_port_attr_set_work);
286
287 dev_hold(dev);
288 asw->dev = dev;
289 memcpy(&asw->attr, attr, sizeof(asw->attr));
290
291 schedule_work(&asw->work);
292
293 return 0;
294}
295
296/**
297 * switchdev_port_attr_set - Set port attribute
298 *
299 * @dev: port device
300 * @attr: attribute to set
301 *
302 * Use a 2-phase prepare-commit transaction model to ensure
303 * system is not left in a partially updated state due to
304 * failure from driver/device.
305 */
306int switchdev_port_attr_set(struct net_device *dev,
307 const struct switchdev_attr *attr)
308{ 255{
309 struct switchdev_trans trans; 256 struct switchdev_trans trans;
310 int err; 257 int err;
311 258
312 if (!rtnl_is_locked()) {
313 /* Running prepare-commit transaction across stacked
314 * devices requires nothing moves, so if rtnl_lock is
315 * not held, schedule a worker thread to hold rtnl_lock
316 * while setting attr.
317 */
318
319 return switchdev_port_attr_set_defer(dev, attr);
320 }
321
322 switchdev_trans_init(&trans); 259 switchdev_trans_init(&trans);
323 260
324 /* Phase I: prepare for attr set. Driver/device should fail 261 /* Phase I: prepare for attr set. Driver/device should fail
@@ -355,6 +292,47 @@ int switchdev_port_attr_set(struct net_device *dev,
355 292
356 return err; 293 return err;
357} 294}
295
296static void switchdev_port_attr_set_deferred(struct net_device *dev,
297 const void *data)
298{
299 const struct switchdev_attr *attr = data;
300 int err;
301
302 err = switchdev_port_attr_set_now(dev, attr);
303 if (err && err != -EOPNOTSUPP)
304 netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n",
305 err, attr->id);
306}
307
308static int switchdev_port_attr_set_defer(struct net_device *dev,
309 const struct switchdev_attr *attr)
310{
311 return switchdev_deferred_enqueue(dev, attr, sizeof(*attr),
312 switchdev_port_attr_set_deferred);
313}
314
315/**
316 * switchdev_port_attr_set - Set port attribute
317 *
318 * @dev: port device
319 * @attr: attribute to set
320 *
321 * Use a 2-phase prepare-commit transaction model to ensure
322 * system is not left in a partially updated state due to
323 * failure from driver/device.
324 *
325 * rtnl_lock must be held and must not be in atomic section,
326 * in case SWITCHDEV_F_DEFER flag is not set.
327 */
328int switchdev_port_attr_set(struct net_device *dev,
329 const struct switchdev_attr *attr)
330{
331 if (attr->flags & SWITCHDEV_F_DEFER)
332 return switchdev_port_attr_set_defer(dev, attr);
333 ASSERT_RTNL();
334 return switchdev_port_attr_set_now(dev, attr);
335}
358EXPORT_SYMBOL_GPL(switchdev_port_attr_set); 336EXPORT_SYMBOL_GPL(switchdev_port_attr_set);
359 337
360static int __switchdev_port_obj_add(struct net_device *dev, 338static int __switchdev_port_obj_add(struct net_device *dev,