aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2009-01-08 17:07:40 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 15:56:46 -0400
commit5d9cb7d276a9c465fef5a771792eac2cf1929f2b (patch)
tree46fb54d0e462debe4016830ee1fa9f7292fb511b
parent77258da403be4cfce84b6abcdb515ad0bd1f92f1 (diff)
firewire: cdev: add ioctls for iso resource management, amendment
Some fixes: - Remove stale documentation. - Fix a != vs. == thinko that got in the way of channel management. - Try bandwidth deallocation even if channel deallocation failed. A simplification: - fw_cdev_allocate_iso_resource.channels is now ordered like libdc1394's dc1394_iso_allocate_channel() channels_allowed argument. By the way, I looked closer at cards from NEC, TI, and VIA, and noticed that they all don't implement IEEE 1394a behaviour which is meant to deviate from IEEE 1212's notion of lock compare-swap. This means that we have to do two lock transactions instead of one in many cases where one transaction would already succeed on a fully 1394a compliant IRM. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-cdev.c2
-rw-r--r--drivers/firewire/fw-iso.c38
-rw-r--r--include/linux/firewire-cdev.h10
3 files changed, 27 insertions, 23 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index b93ad9c0a0d0..257b0c709a8b 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -1082,7 +1082,7 @@ static void iso_resource_work(struct work_struct *work)
1082 spin_unlock_irq(&client->lock); 1082 spin_unlock_irq(&client->lock);
1083 1083
1084 if (todo == ISO_RES_ALLOC && channel >= 0) 1084 if (todo == ISO_RES_ALLOC && channel >= 0)
1085 r->channels = 1ULL << (63 - channel); 1085 r->channels = 1ULL << channel;
1086 1086
1087 if (todo == ISO_RES_REALLOC && success) 1087 if (todo == ISO_RES_REALLOC && success)
1088 goto out; 1088 goto out;
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c
index a7b57b253b06..f511d16efaee 100644
--- a/drivers/firewire/fw-iso.c
+++ b/drivers/firewire/fw-iso.c
@@ -204,17 +204,19 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
204} 204}
205 205
206static int manage_channel(struct fw_card *card, int irm_id, int generation, 206static int manage_channel(struct fw_card *card, int irm_id, int generation,
207 __be32 channels_mask, u64 offset, bool allocate) 207 u32 channels_mask, u64 offset, bool allocate)
208{ 208{
209 __be32 data[2], c, old = allocate ? cpu_to_be32(~0) : 0; 209 __be32 data[2], c, all, old;
210 int i, retry = 5; 210 int i, retry = 5;
211 211
212 old = all = allocate ? cpu_to_be32(~0) : 0;
213
212 for (i = 0; i < 32; i++) { 214 for (i = 0; i < 32; i++) {
213 c = cpu_to_be32(1 << (31 - i)); 215 if (!(channels_mask & 1 << i))
214 if (!(channels_mask & c))
215 continue; 216 continue;
216 217
217 if (allocate == !(old & c)) 218 c = cpu_to_be32(1 << (31 - i));
219 if ((old & c) != (all & c))
218 continue; 220 continue;
219 221
220 data[0] = old; 222 data[0] = old;
@@ -233,7 +235,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
233 old = data[0]; 235 old = data[0];
234 236
235 /* Is the IRM 1394a-2000 compliant? */ 237 /* Is the IRM 1394a-2000 compliant? */
236 if ((data[0] & c) != (data[1] & c)) 238 if ((data[0] & c) == (data[1] & c))
237 continue; 239 continue;
238 240
239 /* 1394-1995 IRM, fall through to retry. */ 241 /* 1394-1995 IRM, fall through to retry. */
@@ -249,11 +251,10 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
249static void deallocate_channel(struct fw_card *card, int irm_id, 251static void deallocate_channel(struct fw_card *card, int irm_id,
250 int generation, int channel) 252 int generation, int channel)
251{ 253{
252 __be32 mask; 254 u32 mask;
253 u64 offset; 255 u64 offset;
254 256
255 mask = channel < 32 ? cpu_to_be32(1 << (31 - channel)) : 257 mask = channel < 32 ? 1 << channel : 1 << (channel - 32);
256 cpu_to_be32(1 << (63 - channel));
257 offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : 258 offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
258 CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; 259 CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;
259 260
@@ -266,7 +267,12 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
266 * In parameters: card, generation, channels_mask, bandwidth, allocate 267 * In parameters: card, generation, channels_mask, bandwidth, allocate
267 * Out parameters: channel, bandwidth 268 * Out parameters: channel, bandwidth
268 * This function blocks (sleeps) during communication with the IRM. 269 * This function blocks (sleeps) during communication with the IRM.
270 *
269 * Allocates or deallocates at most one channel out of channels_mask. 271 * Allocates or deallocates at most one channel out of channels_mask.
272 * channels_mask is a bitfield with MSB for channel 63 and LSB for channel 0.
273 * (Note, the IRM's CHANNELS_AVAILABLE is a big-endian bitfield with MSB for
274 * channel 0 and LSB for channel 63.)
275 * Allocates or deallocates as many bandwidth allocation units as specified.
270 * 276 *
271 * Returns channel < 0 if no channel was allocated or deallocated. 277 * Returns channel < 0 if no channel was allocated or deallocated.
272 * Returns bandwidth = 0 if no bandwidth was allocated or deallocated. 278 * Returns bandwidth = 0 if no bandwidth was allocated or deallocated.
@@ -274,17 +280,17 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
274 * If generation is stale, deallocations succeed but allocations fail with 280 * If generation is stale, deallocations succeed but allocations fail with
275 * channel = -EAGAIN. 281 * channel = -EAGAIN.
276 * 282 *
277 * If channel (de)allocation fails, bandwidth (de)allocation fails too. 283 * If channel allocation fails, no bandwidth will be allocated either.
278 * If bandwidth allocation fails, no channel will be allocated either. 284 * If bandwidth allocation fails, no channel will be allocated either.
279 * If bandwidth deallocation fails, channel deallocation may still have been 285 * But deallocations of channel and bandwidth are tried independently
280 * successful. 286 * of each other's success.
281 */ 287 */
282void fw_iso_resource_manage(struct fw_card *card, int generation, 288void fw_iso_resource_manage(struct fw_card *card, int generation,
283 u64 channels_mask, int *channel, int *bandwidth, 289 u64 channels_mask, int *channel, int *bandwidth,
284 bool allocate) 290 bool allocate)
285{ 291{
286 __be32 channels_hi = cpu_to_be32(channels_mask >> 32); 292 u32 channels_hi = channels_mask; /* channels 31...0 */
287 __be32 channels_lo = cpu_to_be32(channels_mask); 293 u32 channels_lo = channels_mask >> 32; /* channels 63...32 */
288 int irm_id, ret, c = -EINVAL; 294 int irm_id, ret, c = -EINVAL;
289 295
290 spin_lock_irq(&card->lock); 296 spin_lock_irq(&card->lock);
@@ -302,7 +308,7 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
302 } 308 }
303 *channel = c; 309 *channel = c;
304 310
305 if (channels_mask != 0 && c < 0) 311 if (allocate && channels_mask != 0 && c < 0)
306 *bandwidth = 0; 312 *bandwidth = 0;
307 313
308 if (*bandwidth == 0) 314 if (*bandwidth == 0)
@@ -312,7 +318,7 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
312 if (ret < 0) 318 if (ret < 0)
313 *bandwidth = 0; 319 *bandwidth = 0;
314 320
315 if (ret < 0 && c >= 0 && allocate) { 321 if (allocate && ret < 0 && c >= 0) {
316 deallocate_channel(card, irm_id, generation, c); 322 deallocate_channel(card, irm_id, generation, c);
317 *channel = ret; 323 *channel = ret;
318 } 324 }
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 6ed9127680fd..2e35379bf96c 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -174,8 +174,6 @@ struct fw_cdev_event_iso_interrupt {
174 * @handle: Reference by which an allocated resource can be deallocated 174 * @handle: Reference by which an allocated resource can be deallocated
175 * @channel: Isochronous channel which was (de)allocated, if any 175 * @channel: Isochronous channel which was (de)allocated, if any
176 * @bandwidth: Bandwidth allocation units which were (de)allocated, if any 176 * @bandwidth: Bandwidth allocation units which were (de)allocated, if any
177 * @channels_available: Last known availability of channels
178 * @bandwidth_available: Last known availability of bandwidth
179 * 177 *
180 * An %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED event is sent after an isochronous 178 * An %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED event is sent after an isochronous
181 * resource was allocated at the IRM. The client has to check @channel and 179 * resource was allocated at the IRM. The client has to check @channel and
@@ -580,7 +578,7 @@ struct fw_cdev_get_cycle_timer {
580 * 578 *
581 * The %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE ioctl works like 579 * The %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE ioctl works like
582 * %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE except that resources are freed 580 * %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE except that resources are freed
583 * instead of allocated. At most one channel may be specified in this ioctl. 581 * instead of allocated.
584 * An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event concludes this operation. 582 * An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event concludes this operation.
585 * 583 *
586 * To summarize, %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE allocates iso resources 584 * To summarize, %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE allocates iso resources
@@ -588,9 +586,9 @@ struct fw_cdev_get_cycle_timer {
588 * In contrast, %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE allocates iso resources 586 * In contrast, %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE allocates iso resources
589 * for the duration of a bus generation. 587 * for the duration of a bus generation.
590 * 588 *
591 * @channels is a host-endian bitfield with the most significant bit 589 * @channels is a host-endian bitfield with the least significant bit
592 * representing channel 0 and the least significant bit representing channel 63: 590 * representing channel 0 and the most significant bit representing channel 63:
593 * 1ULL << (63 - c) 591 * 1ULL << c for each channel c that is a candidate for (de)allocation.
594 * 592 *
595 * @bandwidth is expressed in bandwidth allocation units, i.e. the time to send 593 * @bandwidth is expressed in bandwidth allocation units, i.e. the time to send
596 * one quadlet of data (payload or header data) at speed S1600. 594 * one quadlet of data (payload or header data) at speed S1600.