summaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-06-14 03:23:49 -0400
committerMarcel Holtmann <marcel@holtmann.org>2019-07-06 06:53:56 -0400
commit40fbb915fd0f4b088f5c9b07061b7d665287d26f (patch)
tree765fb7b8865ae2ecadc9df3c2676ba42374f25e5 /drivers/bluetooth
parentdb50450d096a452ae36dc265575cbff50f0f9f01 (diff)
Bluetooth: hci_ldisc: Add function to wait for characters to be sent
The hci UART line discipline sends its characters in a workqueue. Some devices like the Marvell Bluetooth chips need to make sure that all queued characters are sent before switching the baudrate. This adds a function to synchronize with the workqueue. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/hci_ldisc.c8
-rw-r--r--drivers/bluetooth/hci_uart.h1
2 files changed, 9 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c84f985f348d..8950e07889fe 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -178,6 +178,7 @@ restart:
178 goto restart; 178 goto restart;
179 179
180 clear_bit(HCI_UART_SENDING, &hu->tx_state); 180 clear_bit(HCI_UART_SENDING, &hu->tx_state);
181 wake_up_bit(&hu->tx_state, HCI_UART_SENDING);
181} 182}
182 183
183void hci_uart_init_work(struct work_struct *work) 184void hci_uart_init_work(struct work_struct *work)
@@ -213,6 +214,13 @@ int hci_uart_init_ready(struct hci_uart *hu)
213 return 0; 214 return 0;
214} 215}
215 216
217int hci_uart_wait_until_sent(struct hci_uart *hu)
218{
219 return wait_on_bit_timeout(&hu->tx_state, HCI_UART_SENDING,
220 TASK_INTERRUPTIBLE,
221 msecs_to_jiffies(2000));
222}
223
216/* ------- Interface to HCI layer ------ */ 224/* ------- Interface to HCI layer ------ */
217/* Reset device */ 225/* Reset device */
218static int hci_uart_flush(struct hci_dev *hdev) 226static int hci_uart_flush(struct hci_dev *hdev)
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index d8cf005e3c5d..f11af3912ce6 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -100,6 +100,7 @@ int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p
100void hci_uart_unregister_device(struct hci_uart *hu); 100void hci_uart_unregister_device(struct hci_uart *hu);
101 101
102int hci_uart_tx_wakeup(struct hci_uart *hu); 102int hci_uart_tx_wakeup(struct hci_uart *hu);
103int hci_uart_wait_until_sent(struct hci_uart *hu);
103int hci_uart_init_ready(struct hci_uart *hu); 104int hci_uart_init_ready(struct hci_uart *hu);
104void hci_uart_init_work(struct work_struct *work); 105void hci_uart_init_work(struct work_struct *work);
105void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); 106void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
"hl num">1)); /* * Setup the monitor notification facility. The 1st page for * parent->child and the 2nd page for child->parent */ vmbus_connection.monitor_pages = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1); if (vmbus_connection.monitor_pages == NULL) { ret = -ENOMEM; goto cleanup; } msginfo = kzalloc(sizeof(*msginfo) + sizeof(struct vmbus_channel_initiate_contact), GFP_KERNEL); if (msginfo == NULL) { ret = -ENOMEM; goto cleanup; } init_completion(&msginfo->waitevent); msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; msg->vmbus_version_requested = VMBUS_REVISION_NUMBER; msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages); msg->monitor_page2 = virt_to_phys( (void *)((unsigned long)vmbus_connection.monitor_pages + PAGE_SIZE)); /* * Add to list before we send the request since we may * receive the response before returning from this routine */ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_add_tail(&msginfo->msglistentry, &vmbus_connection.chn_msg_list); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_initiate_contact)); if (ret != 0) { spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&msginfo->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); goto cleanup; } /* Wait for the connection response */ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); if (t == 0) { spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);