[Linux1394-cvslog] rev 746 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2003-02-01 13:59:58
|
Author: dmaas Date: 2003-01-15 03:36:16 -0500 (Wed, 15 Jan 2003) New Revision: 746 Modified: trunk/highlevel.c trunk/highlevel.h trunk/ohci1394.c trunk/ohci1394.h trunk/raw1394.c Log: ohci1394 - allocate legacy API IR context on-demand (this allows new rawiso programs to use multi-channel reception) changed hpsb_listen_channel so that it can return an error if the multichannel context cannot be allocated Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:59:25.000000000 -0500 @@ -170,6 +170,11 @@ static void dma_trm_tasklet(unsigned long data); static void dma_trm_reset(struct dma_trm_ctx *d); +static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, + enum context_type type, int ctx, int num_desc, + int buf_size, int split_buf_size, int context_base); +static void free_dma_rcv_ctx(struct dma_rcv_ctx *d); + static void ohci1394_pci_remove(struct pci_dev *pdev); #ifndef __LITTLE_ENDIAN @@ -415,10 +420,28 @@ d->buf_ind = 0; d->buf_offset = 0; + if(d->type == DMA_CTX_ISO) { + /* Clear contextControl */ + reg_write(ohci, d->ctrlClear, 0xffffffff); + + /* Set bufferFill, isochHeader, multichannel for IR context */ + reg_write(ohci, d->ctrlSet, 0xd0000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, d->ctxtMatch, 0xf0000000); + + /* Clear the multi channel mask high and low registers */ + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); + + /* Set up isoRecvIntMask to generate interrupts */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx); + } + /* Tell the controller where the first AR program is */ reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); - /* Run AR context */ + /* Run context */ reg_write(ohci, d->ctrlSet, 0x00008000); DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); @@ -515,12 +538,6 @@ /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); - /* Set bufferFill, isochHeader, multichannel for IR context */ - reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000); - - /* Set the context match register to match on all tags */ - reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000); - /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); @@ -529,10 +546,6 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); - /* Clear the multi channel mask high and low registers */ - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); - /* Initialize AR dma */ initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); @@ -541,16 +554,9 @@ initialize_dma_trm_ctx(&ohci->at_req_context); initialize_dma_trm_ctx(&ohci->at_resp_context); - /* Initialize IR dma */ - initialize_dma_rcv_ctx(&ohci->ir_context, 1); - /* Initialize IT dma */ initialize_dma_trm_ctx(&ohci->it_context); - /* Set up isoRecvIntMask to generate interrupts for context 0 - (thanks to Michael Greger for seeing that I forgot this) */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); - /* Set up isoXmitIntMask to generate interrupts for context 0 */ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001); @@ -962,8 +968,27 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; } - + + /* activate the legacy IR context */ + if(!ohci->ir_legacy_active) { + if(alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context, + DMA_CTX_ISO, 0, IR_NUM_DESC, + IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase) < 0) { + PRINT(KERN_ERR, ohci->id, + "%s: failed to allocate an IR context", + __FUNCTION__); + return -ENOMEM; + } + ohci->ir_legacy_active = 1; + ohci->ir_legacy_channels = 0; + initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); + + DBGMSG(ohci->id, "ISO receive legacy context activated"); + } + ohci->ISO_channel_usage |= mask; + ohci->ir_legacy_channels |= mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, @@ -1000,6 +1025,7 @@ } ohci->ISO_channel_usage &= ~mask; + ohci->ir_legacy_channels &= ~mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, @@ -1010,6 +1036,12 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "Listening disabled on channel %d", arg); + + if(ohci->ir_legacy_channels == 0 && ohci->ir_legacy_active) { + free_dma_rcv_ctx(&ohci->ir_legacy_context); + DBGMSG(ohci->id, "ISO receive legacy context deactivated"); + ohci->ir_legacy_active = 0; + } break; } default: @@ -2205,7 +2237,7 @@ for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) - PRINT(KERN_ERR, ohci->id, "Async Iso Xmit %d Context died: " + PRINT(KERN_ERR, ohci->id, "Iso Xmit %d Context died: " "ctrl[%08x] cmdptr[%08x]", ctx, reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); @@ -2213,7 +2245,7 @@ for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) - PRINT(KERN_ERR, ohci->id, "Async Iso Recv %d Context died: " + PRINT(KERN_ERR, ohci->id, "Iso Recv %d Context died: " "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx, reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), @@ -2401,8 +2433,10 @@ PRINT(KERN_INFO, ohci->id, "Waking dma ctx=%d ... processing is probably too slow", d->ctx); - reg_write(ohci, d->ctrlSet, 0x1000); } + + /* do this always, to avoid race condition */ + reg_write(ohci, d->ctrlSet, 0x1000); } #define cond_le32_to_cpu(data, noswap) \ @@ -2716,12 +2750,17 @@ DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + if(d->ctrlClear) { + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - if (d->type == DMA_CTX_ISO) - ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet); - else - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) { + /* disable interrupts */ + reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx); + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet); + } else { + tasklet_kill(&d->task); + } + } if (d->buf_cpu) { for (i=0; i<d->num_desc; i++) @@ -2766,9 +2805,9 @@ d->buf_size = buf_size; d->split_buf_size = split_buf_size; - d->ctrlSet = context_base + OHCI1394_ContextControlSet; - d->ctrlClear = context_base + OHCI1394_ContextControlClear; - d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + d->ctrlSet = 0; + d->ctrlClear = 0; + d->cmdPtr = 0; d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); @@ -2836,17 +2875,30 @@ spin_lock_init(&d->lock); if (type == DMA_CTX_ISO) { - ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_MULTICHANNEL_RECEIVE, + ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet, + OHCI_ISO_MULTICHANNEL_RECEIVE, dma_rcv_tasklet, (unsigned long) d); if (ohci1394_register_iso_tasklet(ohci, - &ohci->ir_tasklet) < 0) { + &ohci->ir_legacy_tasklet) < 0) { PRINT(KERN_ERR, ohci->id, "No IR DMA context available"); free_dma_rcv_ctx(d); return -EBUSY; } - } - else + + /* the IR context can be assigned to any DMA context + * by ohci1394_register_iso_tasklet */ + d->ctx = ohci->ir_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx; + d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx; + d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; + d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; + } else { + d->ctrlSet = context_base + OHCI1394_ContextControlSet; + d->ctrlClear = context_base + OHCI1394_ContextControlClear; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d); + } return 0; } @@ -3296,13 +3348,8 @@ ohci->ISO_channel_usage = 0; spin_lock_init(&ohci->IR_channel_lock); - /* IR DMA context */ - if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context, - DMA_CTX_ISO, 0, IR_NUM_DESC, - IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, - OHCI1394_IsoRcvContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate IR context"); - + /* the IR DMA context is allocated on-demand */ + ohci->ir_legacy_active = 0; /* IT DMA context allocation */ if (alloc_dma_trm_ctx(ohci, &ohci->it_context, @@ -3353,7 +3400,8 @@ free_dma_trm_ctx(&ohci->at_resp_context); /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); + if(ohci->ir_legacy_active) + free_dma_rcv_ctx(&ohci->ir_legacy_context); /* Free IT dma */ free_dma_trm_ctx(&ohci->it_context); Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2003-02-01 08:59:25.000000000 -0500 @@ -109,6 +109,7 @@ int ctrlClear; int ctrlSet; int cmdPtr; + int ctxtMatch; }; /* DMA transmit context */ @@ -188,13 +189,21 @@ struct dma_trm_ctx at_req_context; /* iso receive */ - struct dma_rcv_ctx ir_context; - struct ohci1394_iso_tasklet ir_tasklet; - spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ unsigned int ir_multichannel_used; /* ditto */ + spinlock_t IR_channel_lock; + /* iso receive (legacy API) */ + int ir_legacy_active; + u64 ir_legacy_channels; /* note: this differs from ISO_channel_usage; + it only accounts for channels listened to + by the legacy API, so that we can know when + it is safe to free the legacy API context */ + + struct dma_rcv_ctx ir_legacy_context; + struct ohci1394_iso_tasklet ir_legacy_tasklet; + /* iso transmit */ struct dma_trm_ctx it_context; struct ohci1394_iso_tasklet it_tasklet; Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-01 08:59:26.000000000 -0500 @@ -603,10 +603,13 @@ if (fi->listen_channels & (1ULL << channel)) { req->req.error = RAW1394_ERROR_ALREADY; } else { - fi->listen_channels |= 1ULL << channel; - hpsb_listen_channel(hl_handle, fi->host, channel); - fi->iso_buffer = int2ptr(req->req.recvb); - fi->iso_buffer_length = req->req.length; + if(hpsb_listen_channel(hl_handle, fi->host, channel)) { + req->req.error = RAW1394_ERROR_ALREADY; + } else { + fi->listen_channels |= 1ULL << channel; + fi->iso_buffer = int2ptr(req->req.recvb); + fi->iso_buffer_length = req->req.length; + } } } else { /* deallocate channel (one's complement neg) req.misc */ Modified: trunk/highlevel.c ============================================================================== --- trunk/highlevel.c (original) +++ trunk/highlevel.c 2003-02-01 08:59:26.000000000 -0500 @@ -164,16 +164,16 @@ return retval; } -void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, +int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel) { if (channel > 63) { HPSB_ERR("%s called with invalid channel", __FUNCTION__); - return; + return -EINVAL; } if (host->iso_listen_count[channel]++ == 0) { - host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel); + return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel); } } Modified: trunk/highlevel.h ============================================================================== --- trunk/highlevel.h (original) +++ trunk/highlevel.h 2003-02-01 08:59:26.000000000 -0500 @@ -150,8 +150,8 @@ * Enable or disable receving a certain isochronous channel through the * iso_receive op. */ -void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, - unsigned int channel); +int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel); void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel); |