[Linux1394-cvslog] rev 555 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <hog...@li...> - 2002-08-27 22:22:32
|
Author: hogsberg Date: 2002-08-28 03:14:44 -0400 (Wed, 28 Aug 2002) New Revision: 555 Modified: trunk/amdtp.c trunk/dv1394-private.h trunk/dv1394.c trunk/ohci1394.c trunk/ohci1394.h trunk/video1394.c Log: Introduce ohci1394_iso_tasklet interface to the dma contexts of the ohci controller. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -170,10 +170,6 @@ static void ohci1394_pci_remove(struct pci_dev *pdev); -static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, - quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent); - #ifndef __LITTLE_ENDIAN /* Swap a series of quads inplace. */ static __inline__ void block_swab32(quadlet_t *data, size_t size) { @@ -475,34 +471,6 @@ { quadlet_t buf; - /* Start off with a soft reset, to clear everything to a sane - * state. */ - ohci_soft_reset(ohci); - - /* Now enable LPS, which we need in order to start accessing - * most of the registers. In fact, on some cards (ALI M5251), - * accessing registers in the SClk domain without LPS enabled - * will lock up the machine. Wait 50msec to make sure we have - * full link enabled. */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - mdelay(50); - - /* Determine the number of available IR and IT contexts. */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - DBGMSG(ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); - - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - DBGMSG(ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); - - /* Set the usage bits for non-existent contexts so they can't - * be allocated */ - ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx; - ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx; - spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); @@ -1052,6 +1020,30 @@ } } +static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, + quadlet_t rx_event, + quadlet_t tx_event) +{ + struct list_head *lh; + struct ohci1394_iso_tasklet *t; + unsigned long mask; + + spin_lock(&ohci->iso_tasklet_list_lock); + + list_for_each(lh, &ohci->iso_tasklet_list) { + t = list_entry(lh, struct ohci1394_iso_tasklet, link); + mask = 1 << t->context; + + if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) + tasklet_schedule(&t->tasklet); + if (t->type == OHCI_ISO_RECEIVE && rx_event & mask) + tasklet_schedule(&t->tasklet); + } + + spin_unlock(&ohci->iso_tasklet_list_lock); + +} + static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) { @@ -1162,46 +1154,19 @@ event &= ~OHCI1394_RSPkt; } if (event & OHCI1394_isochRx) { - quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = &ohci->ir_context; - isoRecvIntEvent = - reg_read(ohci, OHCI1394_IsoRecvIntEventSet); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, - isoRecvIntEvent); - DBGMSG(ohci->id, "Got isochRx interrupt " - "status=0x%08X isoRecvIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoRecvIntEvent); - if (isoRecvIntEvent & 0x1) { - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "isochRx"); - else - tasklet_schedule(&d->task); - } - - ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0); + quadlet_t rx_event; + rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event); + ohci_schedule_iso_tasklets(ohci, rx_event, 0); event &= ~OHCI1394_isochRx; } if (event & OHCI1394_isochTx) { - quadlet_t isoXmitIntEvent; - struct dma_trm_ctx *d = &ohci->it_context; - isoXmitIntEvent = - reg_read(ohci, OHCI1394_IsoXmitIntEventSet); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, - isoXmitIntEvent); - DBGMSG(ohci->id, "Got isochTx interrupt " - "status=0x%08x isoXmitIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoXmitIntEvent); + quadlet_t tx_event; - ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent); - - if (isoXmitIntEvent & 0x1) { - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "isochTx"); - else - tasklet_schedule(&d->task); - } + tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event); + ohci_schedule_iso_tasklets(ohci, 0, tx_event); event &= ~OHCI1394_isochTx; } if (event & OHCI1394_selfIDComplete) { @@ -1566,21 +1531,24 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) { int i; - struct ti_ohci *ohci; - ohci = d->ohci; + if (d->ohci == NULL) + return; - DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); + DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - ohci1394_stop_context(ohci, d->ctrlClear, NULL); + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet); + else + tasklet_kill(&d->task); if (d->buf_cpu) { for (i=0; i<d->num_desc; i++) if (d->buf_cpu[i] && d->buf_bus[i]) { pci_free_consistent( - ohci->dev, d->buf_size, + d->ohci->dev, d->buf_size, d->buf_cpu[i], d->buf_bus[i]); OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); } @@ -1591,7 +1559,7 @@ for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( - ohci->dev, sizeof(struct dma_cmd), + d->ohci->dev, sizeof(struct dma_cmd), d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); } @@ -1600,9 +1568,8 @@ } if (d->spb) kfree(d->spb); - /* clear ISO context usage bit */ - if (d->type == DMA_CTX_ISO) - clear_bit(d->ctx, &ohci->ir_ctx_usage); + /* Mark this context as freed. */ + d->ohci = NULL; } static int @@ -1612,14 +1579,6 @@ { int i; - if (type == DMA_CTX_ISO) { - /* try to claim the ISO context usage bit */ - if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) { - PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx); - return -EBUSY; - } - } - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1696,30 +1655,43 @@ spin_lock_init(&d->lock); - /* initialize tasklet */ - tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d); + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE, + dma_rcv_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->ir_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IR DMA context available"); + free_dma_rcv_ctx(d); + return -EBUSY; + } + } + else + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d); return 0; } static void free_dma_trm_ctx(struct dma_trm_ctx *d) { - struct ti_ohci *ohci; int i; - ohci = d->ohci; + if (d->ohci == NULL) + return; - DBGMSG(ohci->id, "Freeing dma_trm_ctx %d", d->ctx); + DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx); - ohci1394_stop_context(ohci, d->ctrlClear, NULL); + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->it_tasklet); + else + tasklet_kill(&d->task); if (d->prg_cpu) { for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( - ohci->dev, sizeof(struct at_dma_prg), + d->ohci->dev, sizeof(struct at_dma_prg), d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); } @@ -1727,9 +1699,8 @@ kfree(d->prg_bus); } - /* clear the ISO context usage bit */ - if (d->type == DMA_CTX_ISO) - clear_bit(d->ctx, &ohci->it_ctx_usage); + /* Mark this context as freed. */ + d->ohci = NULL; } static int @@ -1739,14 +1710,6 @@ { int i; - if (type == DMA_CTX_ISO) { - /* try to claim the ISO context usage bit */ - if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) { - PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx); - return -EBUSY; - } - } - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1785,8 +1748,19 @@ spin_lock_init(&d->lock); - /* initialize bottom handler */ - tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); + /* initialize tasklet */ + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT, + dma_rcv_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->it_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); + free_dma_trm_ctx(d); + return -EBUSY; + } + } + else + tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); return 0; } @@ -1990,7 +1964,6 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ unsigned long ohci_base; - int i; if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); @@ -2107,9 +2080,39 @@ OHCI1394_AsRspTrContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AT Resp context"); - ohci->ir_ctx_usage = 0; - ohci->it_ctx_usage = 0; - + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); + + /* Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + mdelay(50); + + /* Determine the number of available IR and IT contexts. */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + /* Set the usage bits for non-existent contexts so they can't + * be allocated */ + ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx; + ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx; + + INIT_LIST_HEAD(&ohci->iso_tasklet_list); + spin_lock_init(&ohci->iso_tasklet_list_lock); + 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, @@ -2124,15 +2127,6 @@ OHCI1394_IsoXmitContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate IT context"); - ohci->ISO_channel_usage = 0; - spin_lock_init(&ohci->IR_channel_lock); - - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } - spin_lock_init(&ohci->irq_hooks_lock); - if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); @@ -2275,81 +2269,69 @@ if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); } -static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, - quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent) +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, + void (*func)(unsigned long), unsigned long data) { - int i; - - spin_lock(&ohci->irq_hooks_lock); - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if(ohci->irq_hooks[i].irq_handler != NULL) { - ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent, - ohci->irq_hooks[i].data); - } - } - spin_unlock(&ohci->irq_hooks_lock); + tasklet_init(&tasklet->tasklet, func, data); + tasklet->type = type; + /* We init the tasklet->link field, so we can list_del() it + * without worrying wether it was added to the list or not. */ + INIT_LIST_HEAD(&tasklet->link); } -int ohci1394_hook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data) +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) { - int i; - int ret = -EBUSY; - unsigned long flags; - - spin_lock_irqsave(&ohci->irq_hooks_lock, flags); - - /* find a free slot */ - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if(ohci->irq_hooks[i].irq_handler == NULL) - break; - } + unsigned long flags, *usage; + int n, i, r = -EBUSY; - if(i >= OHCI1394_MAX_IRQ_HOOKS) - goto out; + if (tasklet->type == OHCI_ISO_TRANSMIT) { + n = ohci->nb_iso_xmit_ctx; + usage = &ohci->it_ctx_usage; + } + else { + n = ohci->nb_iso_rcv_ctx; + usage = &ohci->ir_ctx_usage; + } - ohci->irq_hooks[i].irq_handler = irq_handler; - ohci->irq_hooks[i].data = data; + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - ret = 0; + for (i = 0; i < n; i++) + if (!test_and_set_bit(i, usage)) { + tasklet->context = i; + list_add_tail(&tasklet->link, &ohci->iso_tasklet_list); + r = 0; + break; + } -out: - spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); - return ret; + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - /* ohci1394 will never be unloaded while an IRQ hook is - in use, because the user must reference this symbol */ + return r; } -void ohci1394_unhook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data) +void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) { - int i; unsigned long flags; - - spin_lock_irqsave(&ohci->irq_hooks_lock, flags); - - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if( (ohci->irq_hooks[i].irq_handler == irq_handler) && - (ohci->irq_hooks[i].data == data) ) - break; - } - - if(i < OHCI1394_MAX_IRQ_HOOKS) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } - spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); + tasklet_kill(&tasklet->tasklet); + + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); + + if (tasklet->type == OHCI_ISO_TRANSMIT) + clear_bit(tasklet->context, &ohci->it_ctx_usage); + else + clear_bit(tasklet->context, &ohci->ir_ctx_usage); + + list_del(&tasklet->link); + + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); } EXPORT_SYMBOL(ohci1394_stop_context); -EXPORT_SYMBOL(ohci1394_hook_irq); -EXPORT_SYMBOL(ohci1394_unhook_irq); - +EXPORT_SYMBOL(ohci1394_init_iso_tasklet); +EXPORT_SYMBOL(ohci1394_register_iso_tasklet); +EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet); /*********************************** Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-08-28 03:14:46.000000000 -0400 @@ -251,7 +251,7 @@ struct list_head free_packet_lists; wait_queue_head_t packet_list_wait; spinlock_t packet_list_lock; - int iso_context; + struct ohci1394_iso_tasklet iso_tasklet; struct pci_pool *descriptor_pool, *packet_pool; /* Streams at a host controller are chained through this field. */ @@ -279,23 +279,6 @@ #define OHCI1394_CONTEXT_DEAD 0x00000800 #define OHCI1394_CONTEXT_ACTIVE 0x00000400 -static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci) -{ - int i; - - for (i = 0; i < ohci->nb_iso_xmit_ctx; i++) - if (!test_and_set_bit(i, &ohci->it_ctx_usage)) - return i; - - return -EBUSY; -} - -static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx) -{ - clear_bit(ctx, &ohci->it_ctx_usage); -} - - void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx, dma_addr_t first_cmd, int z, int cycle_match) { @@ -374,7 +357,7 @@ if ((start_cycle & 0x1fff) >= 8000) start_cycle = start_cycle - 8000 + 0x2000; - ohci1394_start_it_ctx(s->host->ohci, s->iso_context, + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, pl->packets[0].db_bus, 3, start_cycle & 0x7fff); } @@ -398,14 +381,15 @@ struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1]; last->db->payload_desc.branch = pl->packets[0].db_bus | 3; last->db->header_desc.skip = pl->packets[0].db_bus | 3; - ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); + ohci1394_wake_it_ctx(s->host->ohci, s->iso_tasklet.context); } else stream_start_dma(s, pl); } -static void stream_shift_packet_lists(struct stream *s) +static void stream_shift_packet_lists(unsigned long l) { + struct stream *s = (struct stream *) l; struct packet_list *pl; struct packet *last; int diff; @@ -539,25 +523,6 @@ return frac->integer + (frac->numerator > 0 ? 1 : 0); } -static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) -{ - struct amdtp_host *host = data; - struct list_head *lh; - struct stream *s = NULL; - - spin_lock(&host->stream_list_lock); - list_for_each(lh, &host->stream_list) { - s = list_entry(lh, struct stream, link); - if (isoXmitIntEvent & (1 << s->iso_context)) - break; - } - spin_unlock(&host->stream_list_lock); - - if (s != NULL) - stream_shift_packet_lists(s); -} - void packet_initialize(struct packet *p, struct packet *next) { /* Here we initialize the dma descriptor block for @@ -918,7 +883,7 @@ stream_start_dma(s, pl); } else { - ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 0); + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); } } @@ -1068,8 +1033,11 @@ init_waitqueue_head(&s->packet_list_wait); spin_lock_init(&s->packet_list_lock); - s->iso_context = ohci1394_alloc_it_ctx(host->ohci); - if (s->iso_context < 0) { + ohci1394_init_iso_tasklet(&s->iso_tasklet, OHCI_ISO_TRANSMIT, + stream_shift_packet_lists, + (unsigned long) s); + + if (ohci1394_register_iso_tasklet(host->ohci, &s->iso_tasklet) < 0) { pci_pool_destroy(s->descriptor_pool); kfree(s->input); kfree(s); @@ -1096,8 +1064,8 @@ wait_event_interruptible(s->packet_list_wait, list_empty(&s->dma_packet_lists)); - ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 1); - ohci1394_free_it_ctx(s->host->ohci, s->iso_context); + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 1); + ohci1394_unregister_iso_tasklet(s->host->ohci, &s->iso_tasklet); if (s->opcr != NULL) cmp_unregister_opcr(s->host->host, s->opcr); @@ -1250,8 +1218,6 @@ spin_lock_irq(&host_list_lock); list_add_tail(&ah->link, &host_list); spin_unlock_irq(&host_list_lock); - - ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah); } static void amdtp_remove_host(struct hpsb_host *host) @@ -1270,7 +1236,6 @@ if (lh != &host_list) { ah = list_entry(lh, struct amdtp_host, link); - ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah); kfree(ah); } else Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-08-28 03:14:46.000000000 -0400 @@ -27,6 +27,7 @@ #define _DV_1394_PRIVATE_H #include "ieee1394.h" +#include "ohci1394.h" #include <linux/pci.h> #include <asm/scatterlist.h> @@ -435,6 +436,7 @@ /* OHCI card IT DMA context number, -1 if not in use */ int ohci_it_ctx; + struct ohci1394_iso_tasklet it_tasklet; /* register offsets for current IT DMA context, 0 if not in use */ u32 ohci_IsoXmitContextControlSet; @@ -442,6 +444,7 @@ u32 ohci_IsoXmitCommandPtr; /* OHCI card IR DMA context number, -1 if not in use */ + struct ohci1394_iso_tasklet ir_tasklet; int ohci_ir_ctx; /* register offsets for current IR DMA context, 0 if not in use */ Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-08-28 03:14:46.000000000 -0400 @@ -139,6 +139,13 @@ int cmdPtr; }; +struct ohci1394_iso_tasklet { + struct tasklet_struct tasklet; + struct list_head link; + int context; + enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type; +}; + struct ti_ohci { int id; /* sequential card number */ @@ -179,12 +186,14 @@ /* 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 */ /* iso transmit */ struct dma_trm_ctx it_context; + struct ohci1394_iso_tasklet it_tasklet; int nb_iso_xmit_ctx; unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ @@ -200,17 +209,11 @@ int self_id_errors; - /* IRQ hooks, for video1394 and dv1394 */ + /* Tasklets for iso receive and transmit, used by video1394, + * amdtp and dv1394 */ -#define OHCI1394_MAX_IRQ_HOOKS 16 - - struct ohci1394_irq_hook { - void (*irq_handler) (int card, quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent, void *data); - void *data; - } irq_hooks[OHCI1394_MAX_IRQ_HOOKS]; - - spinlock_t irq_hooks_lock; + struct list_head iso_tasklet_list; + spinlock_t iso_tasklet_list_lock; /* Swap the selfid buffer? */ unsigned int selfid_swap:1; @@ -399,15 +402,17 @@ #define OHCI1394_TCODE_PHY 0xE -void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg); +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, + int type, + void (*func)(unsigned long), + unsigned long data); +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet); +void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet); + +void ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); struct ti_ohci *ohci1394_get_struct(int card_num); -int ohci1394_hook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data); - -void ohci1394_unhook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data); #endif Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -56,8 +56,6 @@ #include "ohci1394.h" #define ISO_CHANNELS 64 -#define ISO_RECEIVE 0 -#define ISO_TRANSMIT 1 #ifndef virt_to_page #define virt_to_page(x) MAP_NR(x) @@ -84,9 +82,10 @@ struct dma_iso_ctx { struct ti_ohci *ohci; - int type; /* ISO_TRANSMIT or ISO_RECEIVE */ - int ctx; + int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */ + struct ohci1394_iso_tasklet iso_tasklet; int channel; + int ctx; int last_buffer; int * next_buffer; /* For ISO Transmit of video packets to write the correct SYT field @@ -153,8 +152,8 @@ #define PRINT(level, card, fmt, args...) \ printk(level "video1394_%d: " fmt "\n" , card , ## args) -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data); +void wakeup_dma_ir_ctx(unsigned long l); +void wakeup_dma_it_ctx(unsigned long l); static LIST_HEAD(video1394_cards); static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED; @@ -234,12 +233,11 @@ static int free_dma_iso_ctx(struct dma_iso_ctx *d) { int i; - unsigned long *usage; DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx); ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - ohci1394_unhook_irq(d->ohci, irq_handler, d); + ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); if (d->buf) rvfree((void *)d->buf, d->num_desc * d->buf_size); @@ -265,11 +263,6 @@ if (d->next_buffer) kfree(d->next_buffer); - usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage : - &d->ohci->it_ctx_usage; - - /* clear the ISO context usage bit */ - clear_bit(d->ctx, usage); list_del(&d->link); kfree(d); @@ -281,55 +274,29 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, int buf_size, int channel, unsigned int packet_size) { - struct dma_iso_ctx *d=NULL; + struct dma_iso_ctx *d; int i; - unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage : - &ohci->it_ctx_usage; - - /* try to claim the ISO context usage bit */ - for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) { - if (!test_and_set_bit(i, usage)) { - PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i); - break; - } - } - - if (i == ohci->nb_iso_rcv_ctx) { - PRINT(KERN_ERR, ohci->id, "No DMA contexts available"); - return NULL; - } - d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); - if (d==NULL) { + if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_iso_ctx"); return NULL; } - memset(d, 0, sizeof(struct dma_iso_ctx)); + memset(d, 0, sizeof *d); - d->ohci = (void *)ohci; + d->ohci = ohci; d->type = type; - d->ctx = i; d->channel = channel; d->num_desc = num_desc; d->frame_size = buf_size; - if (buf_size%PAGE_SIZE) - d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE); - else - d->buf_size = buf_size; + d->buf_size = (d->buf_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); d->last_buffer = -1; d->buf = NULL; d->ir_prg = NULL; init_waitqueue_head(&d->waitq); - if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) { - PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed"); - free_dma_iso_ctx(d); - return NULL; - } - d->buf = rvmalloc(d->num_desc * d->buf_size); if (d->buf == NULL) { @@ -339,7 +306,24 @@ } memset(d->buf, 0, d->num_desc * d->buf_size); - if (type == ISO_RECEIVE) { + if (type == OHCI_ISO_RECEIVE) + ohci1394_init_iso_tasklet(&d->iso_tasklet, type, + wakeup_dma_ir_ctx, + (unsigned long) d); + else + ohci1394_init_iso_tasklet(&d->iso_tasklet, type, + wakeup_dma_it_ctx, + (unsigned long) d); + + if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "no free iso %s contexts", + type == OHCI_ISO_RECEIVE ? "receive" : "transmit"); + free_dma_iso_ctx(d); + return NULL; + } + d->ctx = d->iso_tasklet.context; + + if (type == OHCI_ISO_RECEIVE) { d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx; d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx; d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx; @@ -359,7 +343,7 @@ d->nb_cmd = d->buf_size / PAGE_SIZE + 1; d->left_size = (d->frame_size % PAGE_SIZE) ? d->frame_size % PAGE_SIZE : PAGE_SIZE; - + for (i=0;i<d->num_desc;i++) { d->ir_prg[i] = kmalloc(d->nb_cmd * sizeof(struct dma_cmd), @@ -371,8 +355,9 @@ return NULL; } } + } - else { /* ISO_TRANSMIT */ + else { /* OHCI_ISO_TRANSMIT */ d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx; d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; @@ -458,7 +443,7 @@ PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", - (type==ISO_RECEIVE) ? "receive" : "transmit", + (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", d->num_desc, d->buf_size, d->frame_size, d->nb_cmd); return d; @@ -563,18 +548,14 @@ return NULL; } -int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) +void wakeup_dma_ir_ctx(unsigned long l) { + struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; int i; - if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "Iso receive event received but " - "context not allocated"); - return -EFAULT; - } - spin_lock(&d->lock); - for (i=0;i<d->num_desc;i++) { + + for (i = 0; i < d->num_desc; i++) { if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; @@ -585,9 +566,11 @@ #endif } } + spin_unlock(&d->lock); - if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); - return 0; + + if (waitqueue_active(&d->waitq)) + wake_up_interruptible(&d->waitq); } static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, @@ -642,29 +625,28 @@ #endif } -int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) +void wakeup_dma_it_ctx(unsigned long l) { + struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; + struct ti_ohci *ohci = d->ohci; int i; - if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "Iso transmit event received but " - "context not allocated"); - return -EFAULT; - } - spin_lock(&d->lock); - for (i=0;i<d->num_desc;i++) { - if (d->it_prg[i][d->last_used_cmd[i]].end.status& - cpu_to_le32(0xFFFF0000)) { + + for (i = 0; i < d->num_desc; i++) { + if (d->it_prg[i][d->last_used_cmd[i]].end.status & + cpu_to_le32(0xFFFF0000)) { int next = d->next_buffer[i]; put_timestamp(ohci, d, next); d->it_prg[i][d->last_used_cmd[i]].end.status = 0; d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); - if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); - return 0; + + if (waitqueue_active(&d->waitq)) + wake_up_interruptible(&d->waitq); } static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) @@ -891,7 +873,7 @@ } if (cmd == VIDEO1394_LISTEN_CHANNEL) { - d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE, + d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE, v.nb_buffers, v.buf_size, v.channel, 0); @@ -912,7 +894,7 @@ d->ctx, v.channel); } else { - d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, + d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT, v.nb_buffers, v.buf_size, v.channel, v.packet_size); @@ -966,9 +948,9 @@ ohci->ISO_channel_usage &= ~mask; if (cmd == VIDEO1394_UNLISTEN_CHANNEL) - d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel); else - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel); if (d == NULL) return -EFAULT; PRINT(KERN_INFO, ohci->id, "Iso context %d " @@ -985,7 +967,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1047,7 +1029,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1128,7 +1110,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1217,7 +1199,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1340,7 +1322,7 @@ ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, "On release: Iso %s context " "%d stop listening on channel %d", - d->type == ISO_RECEIVE ? "receive" : "transmit", + d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit", d->ctx, d->channel); free_dma_iso_ctx(d); } @@ -1352,20 +1334,6 @@ return 0; } -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) -{ - struct dma_iso_ctx *d = (struct dma_iso_ctx *) data; - - DBGMSG(card, "Iso event Recv: %08x Xmit: %08x", - isoRecvIntEvent, isoXmitIntEvent); - - if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx)) - wakeup_dma_ir_ctx(d->ohci, d); - if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx)) - wakeup_dma_it_ctx(d->ohci, d); -} - static struct file_operations video1394_fops= { .owner = THIS_MODULE, Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -159,9 +159,8 @@ reg_read(ohci, OHCI1394_IsochronousCycleTimer); } -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data); - +static void it_tasklet_func(unsigned long data); +static void ir_tasklet_func(unsigned long data); /* GLOBAL DATA */ @@ -1036,39 +1035,34 @@ to clean up the init/shutdown process first.*/ if(video->ohci_it_ctx == -1) { + ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, + it_tasklet_func, (unsigned long) video); - for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) { - - if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) { - video->ohci_it_ctx = i; - debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); - break; - } - } - - if(i == video->ohci->nb_iso_xmit_ctx) { + if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); retval = -EBUSY; goto err_ctx; } + else { + video->ohci_it_ctx = video->it_tasklet.context; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + } } if(video->ohci_ir_ctx == -1) { - for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) { + ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, + ir_tasklet_func, (unsigned long) video); - if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) { - video->ohci_ir_ctx = i; - debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); - break; - } - } - - if(i == video->ohci->nb_iso_rcv_ctx) { + if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); retval = -EBUSY; goto err_ctx; } + else { + video->ohci_ir_ctx = video->ir_tasklet.context; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + } } @@ -1222,11 +1216,11 @@ err_ctx: if(video->ohci_it_ctx != -1) { - clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage); + ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); video->ohci_it_ctx = -1; } if(video->ohci_ir_ctx != -1) { - clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage); + ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); video->ohci_ir_ctx = -1; } @@ -2318,8 +2312,7 @@ /*** DEVICE DRIVER HANDLERS ************************************************/ -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) +static void it_tasklet_func(unsigned long data) { int wake = 0; struct video_card *video = (struct video_card*) data; @@ -2335,7 +2328,6 @@ if( (video->ohci_it_ctx != -1) && - (isoXmitIntEvent & (1 << video->ohci_it_ctx)) && (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { struct frame *f; @@ -2453,14 +2445,25 @@ } /* for(each frame) */ + } - } /* end XMIT portion */ + spin_unlock(&video->spinlock); - /***** RECEIVE INTERRUPT and DMA ACTIVE *****/ + if(wake) { + kill_fasync(&video->fasync, SIGIO, POLL_OUT); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); + } +} - else if( (video->ohci_ir_ctx != -1) && - (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) && - (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { +static void ir_tasklet_func(unsigned long data) +{ + int wake = 0; + struct video_card *video = (struct video_card*) data; + + if( (video->ohci_ir_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { int sof=0; /* start-of-frame flag */ struct frame *f; @@ -2538,15 +2541,8 @@ spin_unlock(&video->spinlock); if(wake) { - - /* send SIGIO */ - - if(isoRecvIntEvent & (1)) - kill_fasync(&video->fasync, SIGIO, POLL_IN); - - if(isoXmitIntEvent & (1)) - kill_fasync(&video->fasync, SIGIO, POLL_OUT); - + kill_fasync(&video->fasync, SIGIO, POLL_IN); + /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } @@ -2714,12 +2710,6 @@ memset(video, 0, sizeof(struct video_card)); - if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) { - printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n"); - goto err_free; - } - - video->ohci = ohci; /* lower 2 bits of id indicate which of four "plugs" per host */ @@ -2795,7 +2785,6 @@ /* obviously nobody has the driver open at this point */ do_dv1394_shutdown(video, 1); - ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video); snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2), (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), (video->mode == MODE_RECEIVE ? "in" : "out") |