aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Lapuyade <eric.lapuyade@linux.intel.com>2012-11-26 12:06:27 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2013-01-09 18:51:48 -0500
commitf0c9103813b3045bd5b43220b6a78c9908a45d24 (patch)
tree78422096c0728f84a43c057bcf6ffa185bd13190
parent5f4d6214ef5e9b1ff6a72ddfa387c1d72adfac98 (diff)
NFC: Fixed nfc core and hci unregistration and cleanup
When an adapter is removed, it will unregister itself from hci and/or nfc core. In order to do that safely, work tasks must first be canceled and prevented to be scheduled again, before the hci or nfc device can be destroyed. Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--include/net/nfc/hci.h2
-rw-r--r--include/net/nfc/nfc.h2
-rw-r--r--net/nfc/core.c47
-rw-r--r--net/nfc/hci/core.c31
-rw-r--r--net/nfc/hci/hcp.c7
5 files changed, 57 insertions, 32 deletions
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 671953e11575..e6224571e5e6 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -87,6 +87,8 @@ struct nfc_hci_dev {
87 87
88 u32 max_data_link_payload; 88 u32 max_data_link_payload;
89 89
90 bool shutting_down;
91
90 struct mutex msg_tx_mutex; 92 struct mutex msg_tx_mutex;
91 93
92 struct list_head msg_tx_queue; 94 struct list_head msg_tx_queue;
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index fce80b2f9be7..1665674e86b2 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -115,6 +115,8 @@ struct nfc_dev {
115 struct timer_list check_pres_timer; 115 struct timer_list check_pres_timer;
116 struct work_struct check_pres_work; 116 struct work_struct check_pres_work;
117 117
118 bool shutting_down;
119
118 struct nfc_ops *ops; 120 struct nfc_ops *ops;
119}; 121};
120#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) 122#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
diff --git a/net/nfc/core.c b/net/nfc/core.c
index aa64ea441676..7d7b4ee34015 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
338 dev->active_target = target; 338 dev->active_target = target;
339 dev->rf_mode = NFC_RF_INITIATOR; 339 dev->rf_mode = NFC_RF_INITIATOR;
340 340
341 if (dev->ops->check_presence) 341 if (dev->ops->check_presence && !dev->shutting_down)
342 mod_timer(&dev->check_pres_timer, jiffies + 342 mod_timer(&dev->check_pres_timer, jiffies +
343 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); 343 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
344 } 344 }
@@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
429 rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb, 429 rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
430 cb_context); 430 cb_context);
431 431
432 if (!rc && dev->ops->check_presence) 432 if (!rc && dev->ops->check_presence && !dev->shutting_down)
433 mod_timer(&dev->check_pres_timer, jiffies + 433 mod_timer(&dev->check_pres_timer, jiffies +
434 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); 434 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
435 } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) { 435 } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
@@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
684 684
685 pr_debug("dev_name=%s\n", dev_name(&dev->dev)); 685 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
686 686
687 if (dev->ops->check_presence) {
688 del_timer_sync(&dev->check_pres_timer);
689 cancel_work_sync(&dev->check_pres_work);
690 }
691
692 nfc_genl_data_exit(&dev->genl_data); 687 nfc_genl_data_exit(&dev->genl_data);
693 kfree(dev->targets); 688 kfree(dev->targets);
694 kfree(dev); 689 kfree(dev);
@@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
706 rc = dev->ops->check_presence(dev, dev->active_target); 701 rc = dev->ops->check_presence(dev, dev->active_target);
707 if (rc == -EOPNOTSUPP) 702 if (rc == -EOPNOTSUPP)
708 goto exit; 703 goto exit;
709 if (!rc) { 704 if (rc) {
710 mod_timer(&dev->check_pres_timer, jiffies +
711 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
712 } else {
713 u32 active_target_idx = dev->active_target->idx; 705 u32 active_target_idx = dev->active_target->idx;
714 device_unlock(&dev->dev); 706 device_unlock(&dev->dev);
715 nfc_target_lost(dev, active_target_idx); 707 nfc_target_lost(dev, active_target_idx);
716 return; 708 return;
717 } 709 }
710
711 if (!dev->shutting_down)
712 mod_timer(&dev->check_pres_timer, jiffies +
713 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
718 } 714 }
719 715
720exit: 716exit:
@@ -853,26 +849,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
853 849
854 id = dev->idx; 850 id = dev->idx;
855 851
856 mutex_lock(&nfc_devlist_mutex); 852 if (dev->ops->check_presence) {
857 nfc_devlist_generation++; 853 device_lock(&dev->dev);
858 854 dev->shutting_down = true;
859 /* lock to avoid unregistering a device while an operation 855 device_unlock(&dev->dev);
860 is in progress */ 856 del_timer_sync(&dev->check_pres_timer);
861 device_lock(&dev->dev); 857 cancel_work_sync(&dev->check_pres_work);
862 device_del(&dev->dev); 858 }
863 device_unlock(&dev->dev);
864 859
865 mutex_unlock(&nfc_devlist_mutex); 860 rc = nfc_genl_device_removed(dev);
861 if (rc)
862 pr_debug("The userspace won't be notified that the device %s "
863 "was removed\n", dev_name(&dev->dev));
866 864
867 nfc_llcp_unregister_device(dev); 865 nfc_llcp_unregister_device(dev);
868 866
869 rc = nfc_genl_device_removed(dev); 867 mutex_lock(&nfc_devlist_mutex);
870 if (rc) 868 nfc_devlist_generation++;
871 pr_debug("The userspace won't be notified that the device %s was removed\n", 869 device_del(&dev->dev);
872 dev_name(&dev->dev)); 870 mutex_unlock(&nfc_devlist_mutex);
873 871
874 ida_simple_remove(&nfc_index_ida, id); 872 ida_simple_remove(&nfc_index_ida, id);
875
876} 873}
877EXPORT_SYMBOL(nfc_unregister_device); 874EXPORT_SYMBOL(nfc_unregister_device);
878 875
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 7bea574d5934..b4b84268653d 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
57 int r = 0; 57 int r = 0;
58 58
59 mutex_lock(&hdev->msg_tx_mutex); 59 mutex_lock(&hdev->msg_tx_mutex);
60 if (hdev->shutting_down)
61 goto exit;
60 62
61 if (hdev->cmd_pending_msg) { 63 if (hdev->cmd_pending_msg) {
62 if (timer_pending(&hdev->cmd_timer) == 0) { 64 if (timer_pending(&hdev->cmd_timer) == 0) {
@@ -868,6 +870,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
868{ 870{
869 struct hci_msg *msg, *n; 871 struct hci_msg *msg, *n;
870 872
873 mutex_lock(&hdev->msg_tx_mutex);
874
875 if (hdev->cmd_pending_msg) {
876 if (hdev->cmd_pending_msg->cb)
877 hdev->cmd_pending_msg->cb(
878 hdev->cmd_pending_msg->cb_context,
879 NULL, -ESHUTDOWN);
880 kfree(hdev->cmd_pending_msg);
881 hdev->cmd_pending_msg = NULL;
882 }
883
884 hdev->shutting_down = true;
885
886 mutex_unlock(&hdev->msg_tx_mutex);
887
888 del_timer_sync(&hdev->cmd_timer);
889 cancel_work_sync(&hdev->msg_tx_work);
890
891 cancel_work_sync(&hdev->msg_rx_work);
892
893 nfc_unregister_device(hdev->ndev);
894
871 skb_queue_purge(&hdev->rx_hcp_frags); 895 skb_queue_purge(&hdev->rx_hcp_frags);
872 skb_queue_purge(&hdev->msg_rx_queue); 896 skb_queue_purge(&hdev->msg_rx_queue);
873 897
@@ -876,13 +900,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
876 skb_queue_purge(&msg->msg_frags); 900 skb_queue_purge(&msg->msg_frags);
877 kfree(msg); 901 kfree(msg);
878 } 902 }
879
880 del_timer_sync(&hdev->cmd_timer);
881
882 nfc_unregister_device(hdev->ndev);
883
884 cancel_work_sync(&hdev->msg_tx_work);
885 cancel_work_sync(&hdev->msg_rx_work);
886} 903}
887EXPORT_SYMBOL(nfc_hci_unregister_device); 904EXPORT_SYMBOL(nfc_hci_unregister_device);
888 905
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c
index bc308a7ca609..b6b4109f2343 100644
--- a/net/nfc/hci/hcp.c
+++ b/net/nfc/hci/hcp.c
@@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
105 } 105 }
106 106
107 mutex_lock(&hdev->msg_tx_mutex); 107 mutex_lock(&hdev->msg_tx_mutex);
108
109 if (hdev->shutting_down) {
110 err = -ESHUTDOWN;
111 mutex_unlock(&hdev->msg_tx_mutex);
112 goto out_skb_err;
113 }
114
108 list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); 115 list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
109 mutex_unlock(&hdev->msg_tx_mutex); 116 mutex_unlock(&hdev->msg_tx_mutex);
110 117