aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/fw-cdev.c')
-rw-r--r--drivers/firewire/fw-cdev.c215
1 files changed, 214 insertions, 1 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 4c33b51b735..a227853aa1e 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -24,6 +24,7 @@
24#include <linux/errno.h> 24#include <linux/errno.h>
25#include <linux/firewire-cdev.h> 25#include <linux/firewire-cdev.h>
26#include <linux/idr.h> 26#include <linux/idr.h>
27#include <linux/jiffies.h>
27#include <linux/kernel.h> 28#include <linux/kernel.h>
28#include <linux/kref.h> 29#include <linux/kref.h>
29#include <linux/mm.h> 30#include <linux/mm.h>
@@ -35,6 +36,7 @@
35#include <linux/time.h> 36#include <linux/time.h>
36#include <linux/vmalloc.h> 37#include <linux/vmalloc.h>
37#include <linux/wait.h> 38#include <linux/wait.h>
39#include <linux/workqueue.h>
38 40
39#include <asm/system.h> 41#include <asm/system.h>
40#include <asm/uaccess.h> 42#include <asm/uaccess.h>
@@ -114,6 +116,21 @@ struct descriptor_resource {
114 u32 data[0]; 116 u32 data[0];
115}; 117};
116 118
119struct iso_resource {
120 struct client_resource resource;
121 struct client *client;
122 /* Schedule work and access todo only with client->lock held. */
123 struct delayed_work work;
124 enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,} todo;
125 int generation;
126 u64 channels;
127 s32 bandwidth;
128 struct iso_resource_event *e_alloc, *e_dealloc;
129};
130
131static void schedule_iso_resource(struct iso_resource *);
132static void release_iso_resource(struct client *, struct client_resource *);
133
117/* 134/*
118 * dequeue_event() just kfree()'s the event, so the event has to be 135 * dequeue_event() just kfree()'s the event, so the event has to be
119 * the first field in a struct XYZ_event. 136 * the first field in a struct XYZ_event.
@@ -145,6 +162,11 @@ struct iso_interrupt_event {
145 struct fw_cdev_event_iso_interrupt interrupt; 162 struct fw_cdev_event_iso_interrupt interrupt;
146}; 163};
147 164
165struct iso_resource_event {
166 struct event event;
167 struct fw_cdev_event_iso_resource resource;
168};
169
148static inline void __user *u64_to_uptr(__u64 value) 170static inline void __user *u64_to_uptr(__u64 value)
149{ 171{
150 return (void __user *)(unsigned long)value; 172 return (void __user *)(unsigned long)value;
@@ -290,6 +312,16 @@ static void for_each_client(struct fw_device *device,
290 mutex_unlock(&device->client_list_mutex); 312 mutex_unlock(&device->client_list_mutex);
291} 313}
292 314
315static int schedule_reallocations(int id, void *p, void *data)
316{
317 struct client_resource *r = p;
318
319 if (r->release == release_iso_resource)
320 schedule_iso_resource(container_of(r,
321 struct iso_resource, resource));
322 return 0;
323}
324
293static void queue_bus_reset_event(struct client *client) 325static void queue_bus_reset_event(struct client *client)
294{ 326{
295 struct bus_reset_event *e; 327 struct bus_reset_event *e;
@@ -304,6 +336,10 @@ static void queue_bus_reset_event(struct client *client)
304 336
305 queue_event(client, &e->event, 337 queue_event(client, &e->event,
306 &e->reset, sizeof(e->reset), NULL, 0); 338 &e->reset, sizeof(e->reset), NULL, 0);
339
340 spin_lock_irq(&client->lock);
341 idr_for_each(&client->resource_idr, schedule_reallocations, client);
342 spin_unlock_irq(&client->lock);
307} 343}
308 344
309void fw_device_cdev_update(struct fw_device *device) 345void fw_device_cdev_update(struct fw_device *device)
@@ -376,8 +412,12 @@ static int add_client_resource(struct client *client,
376 else 412 else
377 ret = idr_get_new(&client->resource_idr, resource, 413 ret = idr_get_new(&client->resource_idr, resource,
378 &resource->handle); 414 &resource->handle);
379 if (ret >= 0) 415 if (ret >= 0) {
380 client_get(client); 416 client_get(client);
417 if (resource->release == release_iso_resource)
418 schedule_iso_resource(container_of(resource,
419 struct iso_resource, resource));
420 }
381 spin_unlock_irqrestore(&client->lock, flags); 421 spin_unlock_irqrestore(&client->lock, flags);
382 422
383 if (ret == -EAGAIN) 423 if (ret == -EAGAIN)
@@ -970,6 +1010,177 @@ static int ioctl_get_cycle_timer(struct client *client, void *buffer)
970 return 0; 1010 return 0;
971} 1011}
972 1012
1013static void iso_resource_work(struct work_struct *work)
1014{
1015 struct iso_resource_event *e;
1016 struct iso_resource *r =
1017 container_of(work, struct iso_resource, work.work);
1018 struct client *client = r->client;
1019 int generation, channel, bandwidth, todo;
1020 bool skip, free, success;
1021
1022 spin_lock_irq(&client->lock);
1023 generation = client->device->generation;
1024 todo = r->todo;
1025 /* Allow 1000ms grace period for other reallocations. */
1026 if (todo == ISO_RES_ALLOC &&
1027 time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
1028 if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
1029 client_get(client);
1030 skip = true;
1031 } else {
1032 /* We could be called twice within the same generation. */
1033 skip = todo == ISO_RES_REALLOC &&
1034 r->generation == generation;
1035 }
1036 free = todo == ISO_RES_DEALLOC;
1037 r->generation = generation;
1038 spin_unlock_irq(&client->lock);
1039
1040 if (skip)
1041 goto out;
1042
1043 bandwidth = r->bandwidth;
1044
1045 fw_iso_resource_manage(client->device->card, generation,
1046 r->channels, &channel, &bandwidth,
1047 todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC);
1048 /*
1049 * Is this generation outdated already? As long as this resource sticks
1050 * in the idr, it will be scheduled again for a newer generation or at
1051 * shutdown.
1052 */
1053 if (channel == -EAGAIN &&
1054 (todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC))
1055 goto out;
1056
1057 success = channel >= 0 || bandwidth > 0;
1058
1059 spin_lock_irq(&client->lock);
1060 /*
1061 * Transit from allocation to reallocation, except if the client
1062 * requested deallocation in the meantime.
1063 */
1064 if (r->todo == ISO_RES_ALLOC)
1065 r->todo = ISO_RES_REALLOC;
1066 /*
1067 * Allocation or reallocation failure? Pull this resource out of the
1068 * idr and prepare for deletion, unless the client is shutting down.
1069 */
1070 if (r->todo == ISO_RES_REALLOC && !success &&
1071 !client->in_shutdown &&
1072 idr_find(&client->resource_idr, r->resource.handle)) {
1073 idr_remove(&client->resource_idr, r->resource.handle);
1074 client_put(client);
1075 free = true;
1076 }
1077 spin_unlock_irq(&client->lock);
1078
1079 if (todo == ISO_RES_ALLOC && channel >= 0)
1080 r->channels = 1ULL << (63 - channel);
1081
1082 if (todo == ISO_RES_REALLOC && success)
1083 goto out;
1084
1085 if (todo == ISO_RES_ALLOC) {
1086 e = r->e_alloc;
1087 r->e_alloc = NULL;
1088 } else {
1089 e = r->e_dealloc;
1090 r->e_dealloc = NULL;
1091 }
1092 e->resource.handle = r->resource.handle;
1093 e->resource.channel = channel;
1094 e->resource.bandwidth = bandwidth;
1095
1096 queue_event(client, &e->event,
1097 &e->resource, sizeof(e->resource), NULL, 0);
1098
1099 if (free) {
1100 cancel_delayed_work(&r->work);
1101 kfree(r->e_alloc);
1102 kfree(r->e_dealloc);
1103 kfree(r);
1104 }
1105 out:
1106 client_put(client);
1107}
1108
1109static void schedule_iso_resource(struct iso_resource *r)
1110{
1111 if (schedule_delayed_work(&r->work, 0))
1112 client_get(r->client);
1113}
1114
1115static void release_iso_resource(struct client *client,
1116 struct client_resource *resource)
1117{
1118 struct iso_resource *r =
1119 container_of(resource, struct iso_resource, resource);
1120
1121 spin_lock_irq(&client->lock);
1122 r->todo = ISO_RES_DEALLOC;
1123 schedule_iso_resource(r);
1124 spin_unlock_irq(&client->lock);
1125}
1126
1127static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
1128{
1129 struct fw_cdev_allocate_iso_resource *request = buffer;
1130 struct iso_resource_event *e1, *e2;
1131 struct iso_resource *r;
1132 int ret;
1133
1134 if ((request->channels == 0 && request->bandwidth == 0) ||
1135 request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL ||
1136 request->bandwidth < 0)
1137 return -EINVAL;
1138
1139 r = kmalloc(sizeof(*r), GFP_KERNEL);
1140 e1 = kmalloc(sizeof(*e1), GFP_KERNEL);
1141 e2 = kmalloc(sizeof(*e2), GFP_KERNEL);
1142 if (r == NULL || e1 == NULL || e2 == NULL) {
1143 ret = -ENOMEM;
1144 goto fail;
1145 }
1146
1147 INIT_DELAYED_WORK(&r->work, iso_resource_work);
1148 r->client = client;
1149 r->todo = ISO_RES_ALLOC;
1150 r->generation = -1;
1151 r->channels = request->channels;
1152 r->bandwidth = request->bandwidth;
1153 r->e_alloc = e1;
1154 r->e_dealloc = e2;
1155
1156 e1->resource.closure = request->closure;
1157 e1->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
1158 e2->resource.closure = request->closure;
1159 e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
1160
1161 r->resource.release = release_iso_resource;
1162 ret = add_client_resource(client, &r->resource, GFP_KERNEL);
1163 if (ret < 0)
1164 goto fail;
1165 request->handle = r->resource.handle;
1166
1167 return 0;
1168 fail:
1169 kfree(r);
1170 kfree(e1);
1171 kfree(e2);
1172
1173 return ret;
1174}
1175
1176static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
1177{
1178 struct fw_cdev_deallocate *request = buffer;
1179
1180 return release_client_resource(client, request->handle,
1181 release_iso_resource, NULL);
1182}
1183
973static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { 1184static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
974 ioctl_get_info, 1185 ioctl_get_info,
975 ioctl_send_request, 1186 ioctl_send_request,
@@ -984,6 +1195,8 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
984 ioctl_start_iso, 1195 ioctl_start_iso,
985 ioctl_stop_iso, 1196 ioctl_stop_iso,
986 ioctl_get_cycle_timer, 1197 ioctl_get_cycle_timer,
1198 ioctl_allocate_iso_resource,
1199 ioctl_deallocate_iso_resource,
987}; 1200};
988 1201
989static int dispatch_ioctl(struct client *client, 1202static int dispatch_ioctl(struct client *client,