aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r--drivers/firewire/core-cdev.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 14bb7b7b5dd7..b1c11775839c 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;
@@ -140,7 +141,6 @@ struct iso_resource {
140 int generation; 141 int generation;
141 u64 channels; 142 u64 channels;
142 s32 bandwidth; 143 s32 bandwidth;
143 __be32 transaction_data[2];
144 struct iso_resource_event *e_alloc, *e_dealloc; 144 struct iso_resource_event *e_alloc, *e_dealloc;
145}; 145};
146 146
@@ -149,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *);
149static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) 149static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
150{ 150{
151 client_get(r->client); 151 client_get(r->client);
152 if (!schedule_delayed_work(&r->work, delay)) 152 if (!queue_delayed_work(fw_workqueue, &r->work, delay))
153 client_put(r->client); 153 client_put(r->client);
154} 154}
155 155
@@ -251,6 +251,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
251 idr_init(&client->resource_idr); 251 idr_init(&client->resource_idr);
252 INIT_LIST_HEAD(&client->event_list); 252 INIT_LIST_HEAD(&client->event_list);
253 init_waitqueue_head(&client->wait); 253 init_waitqueue_head(&client->wait);
254 init_waitqueue_head(&client->tx_flush_wait);
254 INIT_LIST_HEAD(&client->phy_receiver_link); 255 INIT_LIST_HEAD(&client->phy_receiver_link);
255 kref_init(&client->kref); 256 kref_init(&client->kref);
256 257
@@ -520,10 +521,6 @@ static int release_client_resource(struct client *client, u32 handle,
520static void release_transaction(struct client *client, 521static void release_transaction(struct client *client,
521 struct client_resource *resource) 522 struct client_resource *resource)
522{ 523{
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} 524}
528 525
529static void complete_transaction(struct fw_card *card, int rcode, 526static void complete_transaction(struct fw_card *card, int rcode,
@@ -540,22 +537,9 @@ static void complete_transaction(struct fw_card *card, int rcode,
540 memcpy(rsp->data, payload, rsp->length); 537 memcpy(rsp->data, payload, rsp->length);
541 538
542 spin_lock_irqsave(&client->lock, flags); 539 spin_lock_irqsave(&client->lock, flags);
543 /* 540 idr_remove(&client->resource_idr, e->r.resource.handle);
544 * 1. If called while in shutdown, the idr tree must be left untouched. 541 if (client->in_shutdown)
545 * The idr handle will be removed and the client reference will be 542 wake_up(&client->tx_flush_wait);
546 * dropped later.
547 * 2. If the call chain was release_client_resource ->
548 * release_transaction -> complete_transaction (instead of a normal
549 * conclusion of the transaction), i.e. if this resource was already
550 * unregistered from the idr, the client reference will be dropped
551 * by release_client_resource and we must not drop it here.
552 */
553 if (!client->in_shutdown &&
554 idr_find(&client->resource_idr, e->r.resource.handle)) {
555 idr_remove(&client->resource_idr, e->r.resource.handle);
556 /* Drop the idr's reference */
557 client_put(client);
558 }
559 spin_unlock_irqrestore(&client->lock, flags); 543 spin_unlock_irqrestore(&client->lock, flags);
560 544
561 rsp->type = FW_CDEV_EVENT_RESPONSE; 545 rsp->type = FW_CDEV_EVENT_RESPONSE;
@@ -575,7 +559,7 @@ static void complete_transaction(struct fw_card *card, int rcode,
575 queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, 559 queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
576 NULL, 0); 560 NULL, 0);
577 561
578 /* Drop the transaction callback's reference */ 562 /* Drop the idr's reference */
579 client_put(client); 563 client_put(client);
580} 564}
581 565
@@ -614,9 +598,6 @@ static int init_request(struct client *client,
614 if (ret < 0) 598 if (ret < 0)
615 goto failed; 599 goto failed;
616 600
617 /* Get a reference for the transaction callback */
618 client_get(client);
619
620 fw_send_request(client->device->card, &e->r.transaction, 601 fw_send_request(client->device->card, &e->r.transaction,
621 request->tcode, destination_id, request->generation, 602 request->tcode, destination_id, request->generation,
622 speed, request->offset, e->response.data, 603 speed, request->offset, e->response.data,
@@ -1126,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
1126 payload += u.packet.payload_length; 1107 payload += u.packet.payload_length;
1127 count++; 1108 count++;
1128 } 1109 }
1110 fw_iso_context_queue_flush(ctx);
1129 1111
1130 a->size -= uptr_to_u64(p) - a->packets; 1112 a->size -= uptr_to_u64(p) - a->packets;
1131 a->packets = uptr_to_u64(p); 1113 a->packets = uptr_to_u64(p);
@@ -1223,7 +1205,8 @@ static void iso_resource_work(struct work_struct *work)
1223 todo = r->todo; 1205 todo = r->todo;
1224 /* Allow 1000ms grace period for other reallocations. */ 1206 /* Allow 1000ms grace period for other reallocations. */
1225 if (todo == ISO_RES_ALLOC && 1207 if (todo == ISO_RES_ALLOC &&
1226 time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { 1208 time_before64(get_jiffies_64(),
1209 client->device->card->reset_jiffies + HZ)) {
1227 schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3)); 1210 schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
1228 skip = true; 1211 skip = true;
1229 } else { 1212 } else {
@@ -1246,8 +1229,7 @@ static void iso_resource_work(struct work_struct *work)
1246 r->channels, &channel, &bandwidth, 1229 r->channels, &channel, &bandwidth,
1247 todo == ISO_RES_ALLOC || 1230 todo == ISO_RES_ALLOC ||
1248 todo == ISO_RES_REALLOC || 1231 todo == ISO_RES_REALLOC ||
1249 todo == ISO_RES_ALLOC_ONCE, 1232 todo == ISO_RES_ALLOC_ONCE);
1250 r->transaction_data);
1251 /* 1233 /*
1252 * Is this generation outdated already? As long as this resource sticks 1234 * Is this generation outdated already? As long as this resource sticks
1253 * in the idr, it will be scheduled again for a newer generation or at 1235 * in the idr, it will be scheduled again for a newer generation or at
@@ -1501,9 +1483,10 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
1501 e->client = client; 1483 e->client = client;
1502 e->p.speed = SCODE_100; 1484 e->p.speed = SCODE_100;
1503 e->p.generation = a->generation; 1485 e->p.generation = a->generation;
1504 e->p.header[0] = a->data[0]; 1486 e->p.header[0] = TCODE_LINK_INTERNAL << 4;
1505 e->p.header[1] = a->data[1]; 1487 e->p.header[1] = a->data[0];
1506 e->p.header_length = 8; 1488 e->p.header[2] = a->data[1];
1489 e->p.header_length = 12;
1507 e->p.callback = outbound_phy_packet_callback; 1490 e->p.callback = outbound_phy_packet_callback;
1508 e->phy_packet.closure = a->closure; 1491 e->phy_packet.closure = a->closure;
1509 e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT; 1492 e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT;
@@ -1677,6 +1660,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
1677 return ret; 1660 return ret;
1678} 1661}
1679 1662
1663static int is_outbound_transaction_resource(int id, void *p, void *data)
1664{
1665 struct client_resource *resource = p;
1666
1667 return resource->release == release_transaction;
1668}
1669
1670static int has_outbound_transactions(struct client *client)
1671{
1672 int ret;
1673
1674 spin_lock_irq(&client->lock);
1675 ret = idr_for_each(&client->resource_idr,
1676 is_outbound_transaction_resource, NULL);
1677 spin_unlock_irq(&client->lock);
1678
1679 return ret;
1680}
1681
1680static int shutdown_resource(int id, void *p, void *data) 1682static int shutdown_resource(int id, void *p, void *data)
1681{ 1683{
1682 struct client_resource *resource = p; 1684 struct client_resource *resource = p;
@@ -1712,6 +1714,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
1712 client->in_shutdown = true; 1714 client->in_shutdown = true;
1713 spin_unlock_irq(&client->lock); 1715 spin_unlock_irq(&client->lock);
1714 1716
1717 wait_event(client->tx_flush_wait, !has_outbound_transactions(client));
1718
1715 idr_for_each(&client->resource_idr, shutdown_resource, client); 1719 idr_for_each(&client->resource_idr, shutdown_resource, client);
1716 idr_remove_all(&client->resource_idr); 1720 idr_remove_all(&client->resource_idr);
1717 idr_destroy(&client->resource_idr); 1721 idr_destroy(&client->resource_idr);