351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
  2. Date: Fri, 17 Jun 2016 12:29:21 +0200
  3. Subject: [PATCH] brcmfmac: fix lockup when removing P2P interface after event
  4. timeout
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. Removing P2P interface is handled by sending a proper request to the
  9. firmware. On success firmware triggers an event and driver's handler
  10. removes a matching interface.
  11. However on event timeout we remove interface directly from the cfg80211
  12. callback. Current code doesn't handle this case correctly as it always
  13. assumes rtnl to be unlocked.
  14. Fix it by adding an extra rtnl_locked parameter to functions and calling
  15. unregister_netdevice when needed.
  16. Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
  17. Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  18. ---
  19. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  20. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  21. @@ -548,12 +548,16 @@ fail:
  22. return -EBADE;
  23. }
  24. -static void brcmf_net_detach(struct net_device *ndev)
  25. +static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
  26. {
  27. - if (ndev->reg_state == NETREG_REGISTERED)
  28. - unregister_netdev(ndev);
  29. - else
  30. + if (ndev->reg_state == NETREG_REGISTERED) {
  31. + if (rtnl_locked)
  32. + unregister_netdevice(ndev);
  33. + else
  34. + unregister_netdev(ndev);
  35. + } else {
  36. brcmf_cfg80211_free_netdev(ndev);
  37. + }
  38. }
  39. void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
  40. @@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brc
  41. brcmf_err("ERROR: netdev:%s already exists\n",
  42. ifp->ndev->name);
  43. netif_stop_queue(ifp->ndev);
  44. - brcmf_net_detach(ifp->ndev);
  45. + brcmf_net_detach(ifp->ndev, false);
  46. drvr->iflist[bsscfgidx] = NULL;
  47. } else {
  48. brcmf_dbg(INFO, "netdev:%s ignore IF event\n",
  49. @@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brc
  50. return ifp;
  51. }
  52. -static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
  53. +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx,
  54. + bool rtnl_locked)
  55. {
  56. struct brcmf_if *ifp;
  57. @@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pu
  58. cancel_work_sync(&ifp->multicast_work);
  59. cancel_work_sync(&ifp->ndoffload_work);
  60. }
  61. - brcmf_net_detach(ifp->ndev);
  62. + brcmf_net_detach(ifp->ndev, rtnl_locked);
  63. } else {
  64. /* Only p2p device interfaces which get dynamically created
  65. * end up here. In this case the p2p module should be informed
  66. @@ -743,14 +748,14 @@ static void brcmf_del_if(struct brcmf_pu
  67. }
  68. }
  69. -void brcmf_remove_interface(struct brcmf_if *ifp)
  70. +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
  71. {
  72. if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
  73. return;
  74. brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
  75. ifp->ifidx);
  76. brcmf_fws_del_interface(ifp);
  77. - brcmf_del_if(ifp->drvr, ifp->bsscfgidx);
  78. + brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
  79. }
  80. #ifdef CONFIG_INET
  81. @@ -1057,9 +1062,9 @@ fail:
  82. brcmf_fws_deinit(drvr);
  83. }
  84. if (ifp)
  85. - brcmf_net_detach(ifp->ndev);
  86. + brcmf_net_detach(ifp->ndev, false);
  87. if (p2p_ifp)
  88. - brcmf_net_detach(p2p_ifp->ndev);
  89. + brcmf_net_detach(p2p_ifp->ndev, false);
  90. drvr->iflist[0] = NULL;
  91. drvr->iflist[1] = NULL;
  92. if (drvr->settings->ignore_probe_fail)
  93. @@ -1128,7 +1133,7 @@ void brcmf_detach(struct device *dev)
  94. /* make sure primary interface removed last */
  95. for (i = BRCMF_MAX_IFS-1; i > -1; i--)
  96. - brcmf_remove_interface(drvr->iflist[i]);
  97. + brcmf_remove_interface(drvr->iflist[i], false);
  98. brcmf_cfg80211_detach(drvr->config);
  99. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  100. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  101. @@ -216,7 +216,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
  102. int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
  103. struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
  104. bool is_p2pdev, char *name, u8 *mac_addr);
  105. -void brcmf_remove_interface(struct brcmf_if *ifp);
  106. +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
  107. void brcmf_txflowblock_if(struct brcmf_if *ifp,
  108. enum brcmf_netif_stop_reason reason, bool state);
  109. void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
  110. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
  111. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
  112. @@ -183,7 +183,7 @@ static void brcmf_fweh_handle_if_event(s
  113. err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
  114. if (ifp && ifevent->action == BRCMF_E_IF_DEL)
  115. - brcmf_remove_interface(ifp);
  116. + brcmf_remove_interface(ifp, false);
  117. }
  118. /**
  119. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
  120. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
  121. @@ -2289,7 +2289,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
  122. err = 0;
  123. }
  124. if (err)
  125. - brcmf_remove_interface(vif->ifp);
  126. + brcmf_remove_interface(vif->ifp, true);
  127. brcmf_cfg80211_arm_vif_event(cfg, NULL);
  128. if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
  129. @@ -2395,7 +2395,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
  130. if (vif != NULL) {
  131. brcmf_p2p_cancel_remain_on_channel(vif->ifp);
  132. brcmf_p2p_deinit_discovery(p2p);
  133. - brcmf_remove_interface(vif->ifp);
  134. + brcmf_remove_interface(vif->ifp, false);
  135. }
  136. /* just set it all to zero */
  137. memset(p2p, 0, sizeof(*p2p));