aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/core-cdev.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 4434f7ca11d5..5485c0877b81 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -64,6 +64,7 @@ struct client {
64 struct idr resource_idr; 64 struct idr resource_idr;
65 struct list_head event_list; 65 struct list_head event_list;
66 wait_queue_head_t wait; 66 wait_queue_head_t wait;
67 wait_queue_head_t tx_flush_wait;
67 u64 bus_reset_closure; 68 u64 bus_reset_closure;
68 69
69 struct fw_iso_context *iso_context; 70 struct fw_iso_context *iso_context;
@@ -251,6 +252,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
251 idr_init(&client->resource_idr); 252 idr_init(&client->resource_idr);
252 INIT_LIST_HEAD(&client->event_list); 253 INIT_LIST_HEAD(&client->event_list);
253 init_waitqueue_head(&client->wait); 254 init_waitqueue_head(&client->wait);
255 init_waitqueue_head(&client->tx_flush_wait);
254 INIT_LIST_HEAD(&client->phy_receiver_link); 256 INIT_LIST_HEAD(&client->phy_receiver_link);
255 kref_init(&client->kref); 257 kref_init(&client->kref);
256 258
@@ -520,10 +522,6 @@ static int release_client_resource(struct client *client, u32 handle,
520static void release_transaction(struct client *client, 522static void release_transaction(struct client *client,
521 struct client_resource *resource) 523 struct client_resource *resource)
522{ 524{
523 struct outbound_transaction_resource *r = container_of(resource,
524 struct outbound_transaction_resource, resource);
525
526 fw_cancel_transaction(client->device->card, &r->transaction);
527} 525}
528 526
529static void complete_transaction(struct fw_card *card, int rcode, 527static void complete_transaction(struct fw_card *card, int rcode,
@@ -540,16 +538,9 @@ static void complete_transaction(struct fw_card *card, int rcode,
540 memcpy(rsp->data, payload, rsp->length); 538 memcpy(rsp->data, payload, rsp->length);
541 539
542 spin_lock_irqsave(&client->lock, flags); 540 spin_lock_irqsave(&client->lock, flags);
543 /* 541 idr_remove(&client->resource_idr, e->r.resource.handle);
544 * 1. If called while in shutdown, the idr tree must be left untouched. 542 if (client->in_shutdown)
545 * The idr handle will be removed and the client reference will be 543 wake_up(&client->tx_flush_wait);
546 * dropped later.
547 */
548 if (!client->in_shutdown) {
549 idr_remove(&client->resource_idr, e->r.resource.handle);
550 /* Drop the idr's reference */
551 client_put(client);
552 }
553 spin_unlock_irqrestore(&client->lock, flags); 544 spin_unlock_irqrestore(&client->lock, flags);
554 545
555 rsp->type = FW_CDEV_EVENT_RESPONSE; 546 rsp->type = FW_CDEV_EVENT_RESPONSE;
@@ -569,6 +560,8 @@ static void complete_transaction(struct fw_card *card, int rcode,
569 queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, 560 queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
570 NULL, 0); 561 NULL, 0);
571 562
563 /* Drop the idr's reference */
564 client_put(client);
572 /* Drop the transaction callback's reference */ 565 /* Drop the transaction callback's reference */
573 client_put(client); 566 client_put(client);
574} 567}
@@ -1672,6 +1665,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
1672 return ret; 1665 return ret;
1673} 1666}
1674 1667
1668static int is_outbound_transaction_resource(int id, void *p, void *data)
1669{
1670 struct client_resource *resource = p;
1671
1672 return resource->release == release_transaction;
1673}
1674
1675static int has_outbound_transactions(struct client *client)
1676{
1677 int ret;
1678
1679 spin_lock_irq(&client->lock);
1680 ret = idr_for_each(&client->resource_idr,
1681 is_outbound_transaction_resource, NULL);
1682 spin_unlock_irq(&client->lock);
1683
1684 return ret;
1685}
1686
1675static int shutdown_resource(int id, void *p, void *data) 1687static int shutdown_resource(int id, void *p, void *data)
1676{ 1688{
1677 struct client_resource *resource = p; 1689 struct client_resource *resource = p;
@@ -1707,6 +1719,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
1707 client->in_shutdown = true; 1719 client->in_shutdown = true;
1708 spin_unlock_irq(&client->lock); 1720 spin_unlock_irq(&client->lock);
1709 1721
1722 wait_event(client->tx_flush_wait, !has_outbound_transactions(client));
1723
1710 idr_for_each(&client->resource_idr, shutdown_resource, client); 1724 idr_for_each(&client->resource_idr, shutdown_resource, client);
1711 idr_remove_all(&client->resource_idr); 1725 idr_remove_all(&client->resource_idr);
1712 idr_destroy(&client->resource_idr); 1726 idr_destroy(&client->resource_idr);