Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / ieee1394 / iso.c
index f057591..f26680e 100644 (file)
@@ -36,20 +36,22 @@ void hpsb_iso_shutdown(struct hpsb_iso *iso)
        kfree(iso);
 }
 
-static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type,
+static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
+                                            enum hpsb_iso_type type,
                                             unsigned int data_buf_size,
                                             unsigned int buf_packets,
-                                            int channel,
-                                            int dma_mode,
+                                            int channel, int dma_mode,
                                             int irq_interval,
-                                            void (*callback)(struct hpsb_iso*))
+                                            void (*callback) (struct hpsb_iso
+                                                              *))
 {
        struct hpsb_iso *iso;
        int dma_direction;
 
        /* make sure driver supports the ISO API */
        if (!host->driver->isoctl) {
-               printk(KERN_INFO "ieee1394: host driver '%s' does not support the rawiso API\n",
+               printk(KERN_INFO
+                      "ieee1394: host driver '%s' does not support the rawiso API\n",
                       host->driver->name);
                return NULL;
        }
@@ -59,13 +61,14 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i
        if (buf_packets < 2)
                buf_packets = 2;
 
-       if ((dma_mode < HPSB_ISO_DMA_DEFAULT) || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
-               dma_mode=HPSB_ISO_DMA_DEFAULT;
+       if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
+           || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
+               dma_mode = HPSB_ISO_DMA_DEFAULT;
 
-       if (irq_interval == 0)     /* really interrupt for each packet*/
+       if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
+               irq_interval = buf_packets / 4;
+       if (irq_interval == 0)  /* really interrupt for each packet */
                irq_interval = 1;
-       else if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
-               irq_interval = buf_packets / 4;
 
        if (channel < -1 || channel >= 64)
                return NULL;
@@ -76,7 +79,10 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i
 
        /* allocate and write the struct hpsb_iso */
 
-       iso = kmalloc(sizeof(*iso) + buf_packets * sizeof(struct hpsb_iso_packet_info), GFP_KERNEL);
+       iso =
+           kmalloc(sizeof(*iso) +
+                   buf_packets * sizeof(struct hpsb_iso_packet_info),
+                   GFP_KERNEL);
        if (!iso)
                return NULL;
 
@@ -106,21 +112,23 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i
        }
 
        atomic_set(&iso->overflows, 0);
+       iso->bytes_discarded = 0;
        iso->flags = 0;
        iso->prebuffer = 0;
 
        /* allocate the packet buffer */
-       if (dma_region_alloc(&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
+       if (dma_region_alloc
+           (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
                goto err;
 
        return iso;
 
-err:
+      err:
        hpsb_iso_shutdown(iso);
        return NULL;
 }
 
-int hpsb_iso_n_ready(struct hpsb_isoiso)
+int hpsb_iso_n_ready(struct hpsb_iso *iso)
 {
        unsigned long flags;
        int val;
@@ -132,18 +140,19 @@ int hpsb_iso_n_ready(struct hpsb_iso* iso)
        return val;
 }
 
-
-struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
+struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
                                    unsigned int data_buf_size,
                                    unsigned int buf_packets,
                                    int channel,
                                    int speed,
                                    int irq_interval,
-                                   void (*callback)(struct hpsb_iso*))
+                                   void (*callback) (struct hpsb_iso *))
 {
        struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
                                                    data_buf_size, buf_packets,
-                                                   channel, HPSB_ISO_DMA_DEFAULT, irq_interval, callback);
+                                                   channel,
+                                                   HPSB_ISO_DMA_DEFAULT,
+                                                   irq_interval, callback);
        if (!iso)
                return NULL;
 
@@ -156,22 +165,23 @@ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
        iso->flags |= HPSB_ISO_DRIVER_INIT;
        return iso;
 
-err:
+      err:
        hpsb_iso_shutdown(iso);
        return NULL;
 }
 
-struct hpsb_isohpsb_iso_recv_init(struct hpsb_host *host,
+struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
                                    unsigned int data_buf_size,
                                    unsigned int buf_packets,
                                    int channel,
                                    int dma_mode,
                                    int irq_interval,
-                                   void (*callback)(struct hpsb_iso*))
+                                   void (*callback) (struct hpsb_iso *))
 {
        struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
                                                    data_buf_size, buf_packets,
-                                                   channel, dma_mode, irq_interval, callback);
+                                                   channel, dma_mode,
+                                                   irq_interval, callback);
        if (!iso)
                return NULL;
 
@@ -182,7 +192,7 @@ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
        iso->flags |= HPSB_ISO_DRIVER_INIT;
        return iso;
 
-err:
+      err:
        hpsb_iso_shutdown(iso);
        return NULL;
 }
@@ -196,16 +206,17 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
 
 int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
 {
-       if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
-               return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
+       if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
+               return -EINVAL;
+       return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
 }
 
 int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
 {
        if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
                return -EINVAL;
-       return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask);
+       return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
+                                        (unsigned long)&mask);
 }
 
 int hpsb_iso_recv_flush(struct hpsb_iso *iso)
@@ -241,12 +252,12 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
        iso->xmit_cycle = cycle;
 
        if (prebuffer < 0)
-               prebuffer = iso->buf_packets;
+               prebuffer = iso->buf_packets - 1;
        else if (prebuffer == 0)
                prebuffer = 1;
 
-       if (prebuffer > iso->buf_packets)
-               prebuffer = iso->buf_packets;
+       if (prebuffer >= iso->buf_packets)
+               prebuffer = iso->buf_packets - 1;
 
        iso->prebuffer = prebuffer;
 
@@ -282,7 +293,9 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
 
        isoctl_args[2] = sync;
 
-       retval = iso->host->driver->isoctl(iso, RECV_START, (unsigned long) &isoctl_args[0]);
+       retval =
+           iso->host->driver->isoctl(iso, RECV_START,
+                                     (unsigned long)&isoctl_args[0]);
        if (retval)
                return retval;
 
@@ -295,7 +308,8 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
 
 static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
                                     unsigned int offset, unsigned short len,
-                                    unsigned int *out_offset, unsigned short *out_len)
+                                    unsigned int *out_offset,
+                                    unsigned short *out_len)
 {
        if (offset >= iso->buf_size)
                return -EFAULT;
@@ -315,8 +329,8 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
        return 0;
 }
 
-
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy)
+int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
+                              u8 tag, u8 sy)
 {
        struct hpsb_iso_packet_info *info;
        unsigned long flags;
@@ -333,7 +347,8 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag
        info = &iso->infos[iso->first_packet];
 
        /* check for bogus offset/length */
-       if (hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len))
+       if (hpsb_iso_check_offset_len
+           (iso, offset, len, &info->offset, &info->len))
                return -EFAULT;
 
        info->tag = tag;
@@ -341,13 +356,13 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag
 
        spin_lock_irqsave(&iso->lock, flags);
 
-       rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info);
+       rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
        if (rv)
                goto out;
 
        /* increment cursors */
-       iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
-       iso->xmit_cycle = (iso->xmit_cycle+1) % 8000;
+       iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
+       iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
        iso->n_ready_packets--;
 
        if (iso->prebuffer != 0) {
@@ -358,7 +373,7 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag
                }
        }
 
-out:
+      out:
        spin_unlock_irqrestore(&iso->lock, flags);
        return rv;
 }
@@ -368,7 +383,9 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
        if (iso->type != HPSB_ISO_XMIT)
                return -EINVAL;
 
-       return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets);
+       return wait_event_interruptible(iso->waitq,
+                                       hpsb_iso_n_ready(iso) ==
+                                       iso->buf_packets);
 }
 
 void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
@@ -395,7 +412,8 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
 }
 
 void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-                             u16 cycle, u8 channel, u8 tag, u8 sy)
+                             u16 total_len, u16 cycle, u8 channel, u8 tag,
+                             u8 sy)
 {
        unsigned long flags;
        spin_lock_irqsave(&iso->lock, flags);
@@ -403,16 +421,19 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
        if (iso->n_ready_packets == iso->buf_packets) {
                /* overflow! */
                atomic_inc(&iso->overflows);
+               /* Record size of this discarded packet */
+               iso->bytes_discarded += total_len;
        } else {
                struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
                info->offset = offset;
                info->len = len;
+               info->total_len = total_len;
                info->cycle = cycle;
                info->channel = channel;
                info->tag = tag;
                info->sy = sy;
 
-               iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets;
+               iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
                iso->n_ready_packets++;
        }
 
@@ -431,12 +452,24 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
        spin_lock_irqsave(&iso->lock, flags);
        for (i = 0; i < n_packets; i++) {
                rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
-                                              (unsigned long) &iso->infos[iso->first_packet]);
+                                              (unsigned long)&iso->infos[iso->
+                                                                         first_packet]);
                if (rv)
                        break;
 
-               iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
+               iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
                iso->n_ready_packets--;
+
+               /* release memory from packets discarded when queue was full  */
+               if (iso->n_ready_packets == 0) {        /* Release only after all prior packets handled */
+                       if (iso->bytes_discarded != 0) {
+                               struct hpsb_iso_packet_info inf;
+                               inf.total_len = iso->bytes_discarded;
+                               iso->host->driver->isoctl(iso, RECV_RELEASE,
+                                                         (unsigned long)&inf);
+                               iso->bytes_discarded = 0;
+                       }
+               }
        }
        spin_unlock_irqrestore(&iso->lock, flags);
        return rv;