]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/ieee1394/iso.c
Pull bugzilla-7897 into release branch
[linux-2.6.git] / drivers / ieee1394 / iso.c
1 /*
2  * IEEE 1394 for Linux
3  *
4  * kernel ISO transmission/reception
5  *
6  * Copyright (C) 2002 Maas Digital LLC
7  *
8  * This code is licensed under the GPL.  See the file COPYING in the root
9  * directory of the kernel sources for details.
10  */
11
12 #include <linux/pci.h>
13 #include <linux/slab.h>
14
15 #include "hosts.h"
16 #include "iso.h"
17
18 void hpsb_iso_stop(struct hpsb_iso *iso)
19 {
20         if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
21                 return;
22
23         iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
24                                   XMIT_STOP : RECV_STOP, 0);
25         iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
26 }
27
28 void hpsb_iso_shutdown(struct hpsb_iso *iso)
29 {
30         if (iso->flags & HPSB_ISO_DRIVER_INIT) {
31                 hpsb_iso_stop(iso);
32                 iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
33                                           XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
34                 iso->flags &= ~HPSB_ISO_DRIVER_INIT;
35         }
36
37         dma_region_free(&iso->data_buf);
38         kfree(iso);
39 }
40
41 static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
42                                              enum hpsb_iso_type type,
43                                              unsigned int data_buf_size,
44                                              unsigned int buf_packets,
45                                              int channel, int dma_mode,
46                                              int irq_interval,
47                                              void (*callback) (struct hpsb_iso
48                                                                *))
49 {
50         struct hpsb_iso *iso;
51         int dma_direction;
52
53         /* make sure driver supports the ISO API */
54         if (!host->driver->isoctl) {
55                 printk(KERN_INFO
56                        "ieee1394: host driver '%s' does not support the rawiso API\n",
57                        host->driver->name);
58                 return NULL;
59         }
60
61         /* sanitize parameters */
62
63         if (buf_packets < 2)
64                 buf_packets = 2;
65
66         if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
67             || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
68                 dma_mode = HPSB_ISO_DMA_DEFAULT;
69
70         if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
71                 irq_interval = buf_packets / 4;
72         if (irq_interval == 0)  /* really interrupt for each packet */
73                 irq_interval = 1;
74
75         if (channel < -1 || channel >= 64)
76                 return NULL;
77
78         /* channel = -1 is OK for multi-channel recv but not for xmit */
79         if (type == HPSB_ISO_XMIT && channel < 0)
80                 return NULL;
81
82         /* allocate and write the struct hpsb_iso */
83
84         iso =
85             kmalloc(sizeof(*iso) +
86                     buf_packets * sizeof(struct hpsb_iso_packet_info),
87                     GFP_KERNEL);
88         if (!iso)
89                 return NULL;
90
91         iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
92
93         iso->type = type;
94         iso->host = host;
95         iso->hostdata = NULL;
96         iso->callback = callback;
97         init_waitqueue_head(&iso->waitq);
98         iso->channel = channel;
99         iso->irq_interval = irq_interval;
100         iso->dma_mode = dma_mode;
101         dma_region_init(&iso->data_buf);
102         iso->buf_size = PAGE_ALIGN(data_buf_size);
103         iso->buf_packets = buf_packets;
104         iso->pkt_dma = 0;
105         iso->first_packet = 0;
106         spin_lock_init(&iso->lock);
107
108         if (iso->type == HPSB_ISO_XMIT) {
109                 iso->n_ready_packets = iso->buf_packets;
110                 dma_direction = PCI_DMA_TODEVICE;
111         } else {
112                 iso->n_ready_packets = 0;
113                 dma_direction = PCI_DMA_FROMDEVICE;
114         }
115
116         atomic_set(&iso->overflows, 0);
117         iso->bytes_discarded = 0;
118         iso->flags = 0;
119         iso->prebuffer = 0;
120
121         /* allocate the packet buffer */
122         if (dma_region_alloc
123             (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
124                 goto err;
125
126         return iso;
127
128       err:
129         hpsb_iso_shutdown(iso);
130         return NULL;
131 }
132
133 int hpsb_iso_n_ready(struct hpsb_iso *iso)
134 {
135         unsigned long flags;
136         int val;
137
138         spin_lock_irqsave(&iso->lock, flags);
139         val = iso->n_ready_packets;
140         spin_unlock_irqrestore(&iso->lock, flags);
141
142         return val;
143 }
144
145 struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
146                                     unsigned int data_buf_size,
147                                     unsigned int buf_packets,
148                                     int channel,
149                                     int speed,
150                                     int irq_interval,
151                                     void (*callback) (struct hpsb_iso *))
152 {
153         struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
154                                                     data_buf_size, buf_packets,
155                                                     channel,
156                                                     HPSB_ISO_DMA_DEFAULT,
157                                                     irq_interval, callback);
158         if (!iso)
159                 return NULL;
160
161         iso->speed = speed;
162
163         /* tell the driver to start working */
164         if (host->driver->isoctl(iso, XMIT_INIT, 0))
165                 goto err;
166
167         iso->flags |= HPSB_ISO_DRIVER_INIT;
168         return iso;
169
170       err:
171         hpsb_iso_shutdown(iso);
172         return NULL;
173 }
174
175 struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
176                                     unsigned int data_buf_size,
177                                     unsigned int buf_packets,
178                                     int channel,
179                                     int dma_mode,
180                                     int irq_interval,
181                                     void (*callback) (struct hpsb_iso *))
182 {
183         struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
184                                                     data_buf_size, buf_packets,
185                                                     channel, dma_mode,
186                                                     irq_interval, callback);
187         if (!iso)
188                 return NULL;
189
190         /* tell the driver to start working */
191         if (host->driver->isoctl(iso, RECV_INIT, 0))
192                 goto err;
193
194         iso->flags |= HPSB_ISO_DRIVER_INIT;
195         return iso;
196
197       err:
198         hpsb_iso_shutdown(iso);
199         return NULL;
200 }
201
202 int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
203 {
204         if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
205                 return -EINVAL;
206         return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
207 }
208
209 int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
210 {
211         if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
212                 return -EINVAL;
213         return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
214 }
215
216 int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
217 {
218         if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
219                 return -EINVAL;
220         return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
221                                          (unsigned long)&mask);
222 }
223
224 int hpsb_iso_recv_flush(struct hpsb_iso *iso)
225 {
226         if (iso->type != HPSB_ISO_RECV)
227                 return -EINVAL;
228         return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
229 }
230
231 static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
232 {
233         int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
234         if (retval)
235                 return retval;
236
237         iso->flags |= HPSB_ISO_DRIVER_STARTED;
238         return retval;
239 }
240
241 int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
242 {
243         if (iso->type != HPSB_ISO_XMIT)
244                 return -1;
245
246         if (iso->flags & HPSB_ISO_DRIVER_STARTED)
247                 return 0;
248
249         if (cycle < -1)
250                 cycle = -1;
251         else if (cycle >= 8000)
252                 cycle %= 8000;
253
254         iso->xmit_cycle = cycle;
255
256         if (prebuffer < 0)
257                 prebuffer = iso->buf_packets - 1;
258         else if (prebuffer == 0)
259                 prebuffer = 1;
260
261         if (prebuffer >= iso->buf_packets)
262                 prebuffer = iso->buf_packets - 1;
263
264         iso->prebuffer = prebuffer;
265
266         /* remember the starting cycle; DMA will commence from xmit_queue_packets()
267            once enough packets have been buffered */
268         iso->start_cycle = cycle;
269
270         return 0;
271 }
272
273 int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
274 {
275         int retval = 0;
276         int isoctl_args[3];
277
278         if (iso->type != HPSB_ISO_RECV)
279                 return -1;
280
281         if (iso->flags & HPSB_ISO_DRIVER_STARTED)
282                 return 0;
283
284         if (cycle < -1)
285                 cycle = -1;
286         else if (cycle >= 8000)
287                 cycle %= 8000;
288
289         isoctl_args[0] = cycle;
290
291         if (tag_mask < 0)
292                 /* match all tags */
293                 tag_mask = 0xF;
294         isoctl_args[1] = tag_mask;
295
296         isoctl_args[2] = sync;
297
298         retval =
299             iso->host->driver->isoctl(iso, RECV_START,
300                                       (unsigned long)&isoctl_args[0]);
301         if (retval)
302                 return retval;
303
304         iso->flags |= HPSB_ISO_DRIVER_STARTED;
305         return retval;
306 }
307
308 /* check to make sure the user has not supplied bogus values of offset/len
309    that would cause the kernel to access memory outside the buffer */
310
311 static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
312                                      unsigned int offset, unsigned short len,
313                                      unsigned int *out_offset,
314                                      unsigned short *out_len)
315 {
316         if (offset >= iso->buf_size)
317                 return -EFAULT;
318
319         /* make sure the packet does not go beyond the end of the buffer */
320         if (offset + len > iso->buf_size)
321                 return -EFAULT;
322
323         /* check for wrap-around */
324         if (offset + len < offset)
325                 return -EFAULT;
326
327         /* now we can trust 'offset' and 'length' */
328         *out_offset = offset;
329         *out_len = len;
330
331         return 0;
332 }
333
334 int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
335                                u8 tag, u8 sy)
336 {
337         struct hpsb_iso_packet_info *info;
338         unsigned long flags;
339         int rv;
340
341         if (iso->type != HPSB_ISO_XMIT)
342                 return -EINVAL;
343
344         /* is there space in the buffer? */
345         if (iso->n_ready_packets <= 0) {
346                 return -EBUSY;
347         }
348
349         info = &iso->infos[iso->first_packet];
350
351         /* check for bogus offset/length */
352         if (hpsb_iso_check_offset_len
353             (iso, offset, len, &info->offset, &info->len))
354                 return -EFAULT;
355
356         info->tag = tag;
357         info->sy = sy;
358
359         spin_lock_irqsave(&iso->lock, flags);
360
361         rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
362         if (rv)
363                 goto out;
364
365         /* increment cursors */
366         iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
367         iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
368         iso->n_ready_packets--;
369
370         if (iso->prebuffer != 0) {
371                 iso->prebuffer--;
372                 if (iso->prebuffer <= 0) {
373                         iso->prebuffer = 0;
374                         rv = do_iso_xmit_start(iso, iso->start_cycle);
375                 }
376         }
377
378       out:
379         spin_unlock_irqrestore(&iso->lock, flags);
380         return rv;
381 }
382
383 int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
384 {
385         if (iso->type != HPSB_ISO_XMIT)
386                 return -EINVAL;
387
388         return wait_event_interruptible(iso->waitq,
389                                         hpsb_iso_n_ready(iso) ==
390                                         iso->buf_packets);
391 }
392
393 void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
394 {
395         unsigned long flags;
396         spin_lock_irqsave(&iso->lock, flags);
397
398         /* predict the cycle of the next packet to be queued */
399
400         /* jump ahead by the number of packets that are already buffered */
401         cycle += iso->buf_packets - iso->n_ready_packets;
402         cycle %= 8000;
403
404         iso->xmit_cycle = cycle;
405         iso->n_ready_packets++;
406         iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
407
408         if (iso->n_ready_packets == iso->buf_packets || error != 0) {
409                 /* the buffer has run empty! */
410                 atomic_inc(&iso->overflows);
411         }
412
413         spin_unlock_irqrestore(&iso->lock, flags);
414 }
415
416 void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
417                               u16 total_len, u16 cycle, u8 channel, u8 tag,
418                               u8 sy)
419 {
420         unsigned long flags;
421         spin_lock_irqsave(&iso->lock, flags);
422
423         if (iso->n_ready_packets == iso->buf_packets) {
424                 /* overflow! */
425                 atomic_inc(&iso->overflows);
426                 /* Record size of this discarded packet */
427                 iso->bytes_discarded += total_len;
428         } else {
429                 struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
430                 info->offset = offset;
431                 info->len = len;
432                 info->total_len = total_len;
433                 info->cycle = cycle;
434                 info->channel = channel;
435                 info->tag = tag;
436                 info->sy = sy;
437
438                 iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
439                 iso->n_ready_packets++;
440         }
441
442         spin_unlock_irqrestore(&iso->lock, flags);
443 }
444
445 int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
446 {
447         unsigned long flags;
448         unsigned int i;
449         int rv = 0;
450
451         if (iso->type != HPSB_ISO_RECV)
452                 return -1;
453
454         spin_lock_irqsave(&iso->lock, flags);
455         for (i = 0; i < n_packets; i++) {
456                 rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
457                                                (unsigned long)&iso->infos[iso->
458                                                                           first_packet]);
459                 if (rv)
460                         break;
461
462                 iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
463                 iso->n_ready_packets--;
464
465                 /* release memory from packets discarded when queue was full  */
466                 if (iso->n_ready_packets == 0) {        /* Release only after all prior packets handled */
467                         if (iso->bytes_discarded != 0) {
468                                 struct hpsb_iso_packet_info inf;
469                                 inf.total_len = iso->bytes_discarded;
470                                 iso->host->driver->isoctl(iso, RECV_RELEASE,
471                                                           (unsigned long)&inf);
472                                 iso->bytes_discarded = 0;
473                         }
474                 }
475         }
476         spin_unlock_irqrestore(&iso->lock, flags);
477         return rv;
478 }
479
480 void hpsb_iso_wake(struct hpsb_iso *iso)
481 {
482         wake_up_interruptible(&iso->waitq);
483
484         if (iso->callback)
485                 iso->callback(iso);
486 }