diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2015-04-03 02:56:21 -0400 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2015-04-13 02:01:00 -0400 |
commit | 24e94454c8cb6a13634f5a2f5a01da53a546a58d (patch) | |
tree | 97428ea550eb6c74ed239c3e2efd94369d9734e5 /arch/xtensa/platforms/iss/network.c | |
parent | 39a8804455fb23f09157341d3ba7db6d7ae6ee76 (diff) |
xtensa: ISS: fix locking in TAP network adapter
- don't lock lp->lock in the iss_net_timer for the call of iss_net_poll,
it will lock it itself;
- invert order of lp->lock and opened_lock acquisition in the
iss_net_open to make it consistent with iss_net_poll;
- replace spin_lock with spin_lock_bh when acquiring locks used in
iss_net_timer from non-atomic context;
- replace spin_lock_irqsave with spin_lock_bh in the iss_net_start_xmit
as the driver doesn't use lp->lock in the hard IRQ context;
- replace __SPIN_LOCK_UNLOCKED(lp.lock) with spin_lock_init, otherwise
lockdep is unhappy about using non-static key.
Cc: <stable@vger.kernel.org>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/platforms/iss/network.c')
-rw-r--r-- | arch/xtensa/platforms/iss/network.c | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index d05f8feeb8d7..17b1ef3232e4 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c | |||
@@ -349,8 +349,8 @@ static void iss_net_timer(unsigned long priv) | |||
349 | { | 349 | { |
350 | struct iss_net_private *lp = (struct iss_net_private *)priv; | 350 | struct iss_net_private *lp = (struct iss_net_private *)priv; |
351 | 351 | ||
352 | spin_lock(&lp->lock); | ||
353 | iss_net_poll(); | 352 | iss_net_poll(); |
353 | spin_lock(&lp->lock); | ||
354 | mod_timer(&lp->timer, jiffies + lp->timer_val); | 354 | mod_timer(&lp->timer, jiffies + lp->timer_val); |
355 | spin_unlock(&lp->lock); | 355 | spin_unlock(&lp->lock); |
356 | } | 356 | } |
@@ -361,7 +361,7 @@ static int iss_net_open(struct net_device *dev) | |||
361 | struct iss_net_private *lp = netdev_priv(dev); | 361 | struct iss_net_private *lp = netdev_priv(dev); |
362 | int err; | 362 | int err; |
363 | 363 | ||
364 | spin_lock(&lp->lock); | 364 | spin_lock_bh(&lp->lock); |
365 | 365 | ||
366 | err = lp->tp.open(lp); | 366 | err = lp->tp.open(lp); |
367 | if (err < 0) | 367 | if (err < 0) |
@@ -376,9 +376,11 @@ static int iss_net_open(struct net_device *dev) | |||
376 | while ((err = iss_net_rx(dev)) > 0) | 376 | while ((err = iss_net_rx(dev)) > 0) |
377 | ; | 377 | ; |
378 | 378 | ||
379 | spin_lock(&opened_lock); | 379 | spin_unlock_bh(&lp->lock); |
380 | spin_lock_bh(&opened_lock); | ||
380 | list_add(&lp->opened_list, &opened); | 381 | list_add(&lp->opened_list, &opened); |
381 | spin_unlock(&opened_lock); | 382 | spin_unlock_bh(&opened_lock); |
383 | spin_lock_bh(&lp->lock); | ||
382 | 384 | ||
383 | init_timer(&lp->timer); | 385 | init_timer(&lp->timer); |
384 | lp->timer_val = ISS_NET_TIMER_VALUE; | 386 | lp->timer_val = ISS_NET_TIMER_VALUE; |
@@ -387,7 +389,7 @@ static int iss_net_open(struct net_device *dev) | |||
387 | mod_timer(&lp->timer, jiffies + lp->timer_val); | 389 | mod_timer(&lp->timer, jiffies + lp->timer_val); |
388 | 390 | ||
389 | out: | 391 | out: |
390 | spin_unlock(&lp->lock); | 392 | spin_unlock_bh(&lp->lock); |
391 | return err; | 393 | return err; |
392 | } | 394 | } |
393 | 395 | ||
@@ -395,7 +397,7 @@ static int iss_net_close(struct net_device *dev) | |||
395 | { | 397 | { |
396 | struct iss_net_private *lp = netdev_priv(dev); | 398 | struct iss_net_private *lp = netdev_priv(dev); |
397 | netif_stop_queue(dev); | 399 | netif_stop_queue(dev); |
398 | spin_lock(&lp->lock); | 400 | spin_lock_bh(&lp->lock); |
399 | 401 | ||
400 | spin_lock(&opened_lock); | 402 | spin_lock(&opened_lock); |
401 | list_del(&opened); | 403 | list_del(&opened); |
@@ -405,18 +407,17 @@ static int iss_net_close(struct net_device *dev) | |||
405 | 407 | ||
406 | lp->tp.close(lp); | 408 | lp->tp.close(lp); |
407 | 409 | ||
408 | spin_unlock(&lp->lock); | 410 | spin_unlock_bh(&lp->lock); |
409 | return 0; | 411 | return 0; |
410 | } | 412 | } |
411 | 413 | ||
412 | static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) | 414 | static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) |
413 | { | 415 | { |
414 | struct iss_net_private *lp = netdev_priv(dev); | 416 | struct iss_net_private *lp = netdev_priv(dev); |
415 | unsigned long flags; | ||
416 | int len; | 417 | int len; |
417 | 418 | ||
418 | netif_stop_queue(dev); | 419 | netif_stop_queue(dev); |
419 | spin_lock_irqsave(&lp->lock, flags); | 420 | spin_lock_bh(&lp->lock); |
420 | 421 | ||
421 | len = lp->tp.write(lp, &skb); | 422 | len = lp->tp.write(lp, &skb); |
422 | 423 | ||
@@ -438,7 +439,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
438 | pr_err("%s: %s failed(%d)\n", dev->name, __func__, len); | 439 | pr_err("%s: %s failed(%d)\n", dev->name, __func__, len); |
439 | } | 440 | } |
440 | 441 | ||
441 | spin_unlock_irqrestore(&lp->lock, flags); | 442 | spin_unlock_bh(&lp->lock); |
442 | 443 | ||
443 | dev_kfree_skb(skb); | 444 | dev_kfree_skb(skb); |
444 | return NETDEV_TX_OK; | 445 | return NETDEV_TX_OK; |
@@ -466,9 +467,9 @@ static int iss_net_set_mac(struct net_device *dev, void *addr) | |||
466 | 467 | ||
467 | if (!is_valid_ether_addr(hwaddr->sa_data)) | 468 | if (!is_valid_ether_addr(hwaddr->sa_data)) |
468 | return -EADDRNOTAVAIL; | 469 | return -EADDRNOTAVAIL; |
469 | spin_lock(&lp->lock); | 470 | spin_lock_bh(&lp->lock); |
470 | memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); | 471 | memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); |
471 | spin_unlock(&lp->lock); | 472 | spin_unlock_bh(&lp->lock); |
472 | return 0; | 473 | return 0; |
473 | } | 474 | } |
474 | 475 | ||
@@ -520,11 +521,11 @@ static int iss_net_configure(int index, char *init) | |||
520 | *lp = (struct iss_net_private) { | 521 | *lp = (struct iss_net_private) { |
521 | .device_list = LIST_HEAD_INIT(lp->device_list), | 522 | .device_list = LIST_HEAD_INIT(lp->device_list), |
522 | .opened_list = LIST_HEAD_INIT(lp->opened_list), | 523 | .opened_list = LIST_HEAD_INIT(lp->opened_list), |
523 | .lock = __SPIN_LOCK_UNLOCKED(lp.lock), | ||
524 | .dev = dev, | 524 | .dev = dev, |
525 | .index = index, | 525 | .index = index, |
526 | }; | 526 | }; |
527 | 527 | ||
528 | spin_lock_init(&lp->lock); | ||
528 | /* | 529 | /* |
529 | * If this name ends up conflicting with an existing registered | 530 | * If this name ends up conflicting with an existing registered |
530 | * netdevice, that is OK, register_netdev{,ice}() will notice this | 531 | * netdevice, that is OK, register_netdev{,ice}() will notice this |