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>
This commit is contained in:
parent
5f4d6214ef
commit
f0c9103813
|
@ -87,6 +87,8 @@ struct nfc_hci_dev {
|
||||||
|
|
||||||
u32 max_data_link_payload;
|
u32 max_data_link_payload;
|
||||||
|
|
||||||
|
bool shutting_down;
|
||||||
|
|
||||||
struct mutex msg_tx_mutex;
|
struct mutex msg_tx_mutex;
|
||||||
|
|
||||||
struct list_head msg_tx_queue;
|
struct list_head msg_tx_queue;
|
||||||
|
|
|
@ -115,6 +115,8 @@ struct nfc_dev {
|
||||||
struct timer_list check_pres_timer;
|
struct timer_list check_pres_timer;
|
||||||
struct work_struct check_pres_work;
|
struct work_struct check_pres_work;
|
||||||
|
|
||||||
|
bool shutting_down;
|
||||||
|
|
||||||
struct nfc_ops *ops;
|
struct nfc_ops *ops;
|
||||||
};
|
};
|
||||||
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
||||||
|
|
|
@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
|
||||||
dev->active_target = target;
|
dev->active_target = target;
|
||||||
dev->rf_mode = NFC_RF_INITIATOR;
|
dev->rf_mode = NFC_RF_INITIATOR;
|
||||||
|
|
||||||
if (dev->ops->check_presence)
|
if (dev->ops->check_presence && !dev->shutting_down)
|
||||||
mod_timer(&dev->check_pres_timer, jiffies +
|
mod_timer(&dev->check_pres_timer, jiffies +
|
||||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
|
||||||
rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
|
rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
|
||||||
cb_context);
|
cb_context);
|
||||||
|
|
||||||
if (!rc && dev->ops->check_presence)
|
if (!rc && dev->ops->check_presence && !dev->shutting_down)
|
||||||
mod_timer(&dev->check_pres_timer, jiffies +
|
mod_timer(&dev->check_pres_timer, jiffies +
|
||||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||||
} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
|
} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
|
||||||
|
@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
|
||||||
|
|
||||||
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
|
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
|
||||||
|
|
||||||
if (dev->ops->check_presence) {
|
|
||||||
del_timer_sync(&dev->check_pres_timer);
|
|
||||||
cancel_work_sync(&dev->check_pres_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
nfc_genl_data_exit(&dev->genl_data);
|
nfc_genl_data_exit(&dev->genl_data);
|
||||||
kfree(dev->targets);
|
kfree(dev->targets);
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
|
@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
|
||||||
rc = dev->ops->check_presence(dev, dev->active_target);
|
rc = dev->ops->check_presence(dev, dev->active_target);
|
||||||
if (rc == -EOPNOTSUPP)
|
if (rc == -EOPNOTSUPP)
|
||||||
goto exit;
|
goto exit;
|
||||||
if (!rc) {
|
if (rc) {
|
||||||
mod_timer(&dev->check_pres_timer, jiffies +
|
|
||||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
|
||||||
} else {
|
|
||||||
u32 active_target_idx = dev->active_target->idx;
|
u32 active_target_idx = dev->active_target->idx;
|
||||||
device_unlock(&dev->dev);
|
device_unlock(&dev->dev);
|
||||||
nfc_target_lost(dev, active_target_idx);
|
nfc_target_lost(dev, active_target_idx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dev->shutting_down)
|
||||||
|
mod_timer(&dev->check_pres_timer, jiffies +
|
||||||
|
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -853,26 +849,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
|
||||||
|
|
||||||
id = dev->idx;
|
id = dev->idx;
|
||||||
|
|
||||||
mutex_lock(&nfc_devlist_mutex);
|
if (dev->ops->check_presence) {
|
||||||
nfc_devlist_generation++;
|
device_lock(&dev->dev);
|
||||||
|
dev->shutting_down = true;
|
||||||
/* lock to avoid unregistering a device while an operation
|
device_unlock(&dev->dev);
|
||||||
is in progress */
|
del_timer_sync(&dev->check_pres_timer);
|
||||||
device_lock(&dev->dev);
|
cancel_work_sync(&dev->check_pres_work);
|
||||||
device_del(&dev->dev);
|
}
|
||||||
device_unlock(&dev->dev);
|
|
||||||
|
|
||||||
mutex_unlock(&nfc_devlist_mutex);
|
|
||||||
|
|
||||||
nfc_llcp_unregister_device(dev);
|
|
||||||
|
|
||||||
rc = nfc_genl_device_removed(dev);
|
rc = nfc_genl_device_removed(dev);
|
||||||
if (rc)
|
if (rc)
|
||||||
pr_debug("The userspace won't be notified that the device %s was removed\n",
|
pr_debug("The userspace won't be notified that the device %s "
|
||||||
dev_name(&dev->dev));
|
"was removed\n", dev_name(&dev->dev));
|
||||||
|
|
||||||
|
nfc_llcp_unregister_device(dev);
|
||||||
|
|
||||||
|
mutex_lock(&nfc_devlist_mutex);
|
||||||
|
nfc_devlist_generation++;
|
||||||
|
device_del(&dev->dev);
|
||||||
|
mutex_unlock(&nfc_devlist_mutex);
|
||||||
|
|
||||||
ida_simple_remove(&nfc_index_ida, id);
|
ida_simple_remove(&nfc_index_ida, id);
|
||||||
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nfc_unregister_device);
|
EXPORT_SYMBOL(nfc_unregister_device);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
mutex_lock(&hdev->msg_tx_mutex);
|
mutex_lock(&hdev->msg_tx_mutex);
|
||||||
|
if (hdev->shutting_down)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
if (hdev->cmd_pending_msg) {
|
if (hdev->cmd_pending_msg) {
|
||||||
if (timer_pending(&hdev->cmd_timer) == 0) {
|
if (timer_pending(&hdev->cmd_timer) == 0) {
|
||||||
|
@ -868,6 +870,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_msg *msg, *n;
|
struct hci_msg *msg, *n;
|
||||||
|
|
||||||
|
mutex_lock(&hdev->msg_tx_mutex);
|
||||||
|
|
||||||
|
if (hdev->cmd_pending_msg) {
|
||||||
|
if (hdev->cmd_pending_msg->cb)
|
||||||
|
hdev->cmd_pending_msg->cb(
|
||||||
|
hdev->cmd_pending_msg->cb_context,
|
||||||
|
NULL, -ESHUTDOWN);
|
||||||
|
kfree(hdev->cmd_pending_msg);
|
||||||
|
hdev->cmd_pending_msg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdev->shutting_down = true;
|
||||||
|
|
||||||
|
mutex_unlock(&hdev->msg_tx_mutex);
|
||||||
|
|
||||||
|
del_timer_sync(&hdev->cmd_timer);
|
||||||
|
cancel_work_sync(&hdev->msg_tx_work);
|
||||||
|
|
||||||
|
cancel_work_sync(&hdev->msg_rx_work);
|
||||||
|
|
||||||
|
nfc_unregister_device(hdev->ndev);
|
||||||
|
|
||||||
skb_queue_purge(&hdev->rx_hcp_frags);
|
skb_queue_purge(&hdev->rx_hcp_frags);
|
||||||
skb_queue_purge(&hdev->msg_rx_queue);
|
skb_queue_purge(&hdev->msg_rx_queue);
|
||||||
|
|
||||||
|
@ -876,13 +900,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||||
skb_queue_purge(&msg->msg_frags);
|
skb_queue_purge(&msg->msg_frags);
|
||||||
kfree(msg);
|
kfree(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
del_timer_sync(&hdev->cmd_timer);
|
|
||||||
|
|
||||||
nfc_unregister_device(hdev->ndev);
|
|
||||||
|
|
||||||
cancel_work_sync(&hdev->msg_tx_work);
|
|
||||||
cancel_work_sync(&hdev->msg_rx_work);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nfc_hci_unregister_device);
|
EXPORT_SYMBOL(nfc_hci_unregister_device);
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&hdev->msg_tx_mutex);
|
mutex_lock(&hdev->msg_tx_mutex);
|
||||||
|
|
||||||
|
if (hdev->shutting_down) {
|
||||||
|
err = -ESHUTDOWN;
|
||||||
|
mutex_unlock(&hdev->msg_tx_mutex);
|
||||||
|
goto out_skb_err;
|
||||||
|
}
|
||||||
|
|
||||||
list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
|
list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
|
||||||
mutex_unlock(&hdev->msg_tx_mutex);
|
mutex_unlock(&hdev->msg_tx_mutex);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue