summaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2015-10-14 13:40:50 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-15 09:09:48 -0400
commit0bc05d585d381c30de3fdf955730df31593d2101 (patch)
tree67c6871b0b123fe73507273b9a50a53f0e0e1010 /net/switchdev/switchdev.c
parentf7fadf3047d005d17376da65aa9e5734f45a77d4 (diff)
switchdev: allow caller to explicitly request attr_set as deferred
Caller should know if he can call attr_set directly (when holding RTNL) or if he has to defer the att_set processing for later. This also allows drivers to sleep inside attr_set and report operation status back to switchdev core. Switchdev core then warns if status is not ok, instead of silent errors happening in drivers. Benefit from newly introduced switchdev deferred ops infrastructure. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
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,