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