From: Frank Mori Hess Date: Thu, 26 Apr 2007 17:43:44 +0000 (+0000) Subject: Changed request/release of mite channels to use mite_channel struct X-Git-Tag: r0_7_74~98 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=79761528110304192200526dbbb050a5a19eca99;p=comedi.git Changed request/release of mite channels to use mite_channel struct pointers, instead of channel indices. Changed many mite functions to take mite_channel argument instead of a mite_struct and a channel index. Added mite_dma_descriptor_ring, since drivers need to maintain the descriptors seperatly from a channel, since the channel is reserved/released with each use but the descriptor ring only changes when comedi's buffer is resized. Made ni_mio_common.c dynamically allocate mite channels for ai/ao when needed, instead of permanently assigning mite channels to subdevices. --- diff --git a/comedi/drivers/mite.c b/comedi/drivers/mite.c index 076c8e57..35df00dc 100644 --- a/comedi/drivers/mite.c +++ b/comedi/drivers/mite.c @@ -76,6 +76,8 @@ void mite_init(void) for(pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL ; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { if(pcidev->vendor==PCI_VENDOR_ID_NATINST){ + unsigned i; + mite=kmalloc(sizeof(*mite),GFP_KERNEL); if(!mite){ printk("mite: allocation failed\n"); @@ -85,7 +87,11 @@ void mite_init(void) memset(mite,0,sizeof(*mite)); spin_lock_init(&mite->lock); mite->pcidev=pci_dev_get(pcidev); - + for(i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) + { + mite->channels[i].mite = mite; + mite->channels[i].channel = i; + } mite->next=mite_devices; mite_devices=mite; } @@ -190,6 +196,7 @@ void mite_unsetup(struct mite_struct *mite) if(!mite)return; + pci_disable_device(mite->pcidev); if(mite->mite_io_addr){ iounmap(mite->mite_io_addr); mite->mite_io_addr=NULL; @@ -222,64 +229,66 @@ void mite_list_devices(void) } -int mite_alloc_channel(struct mite_struct *mite) +struct mite_channel* mite_offset_request_channel(struct mite_struct *mite, struct mite_dma_descriptor_ring *ring, + unsigned first_channel_to_try) { int i; unsigned long flags; - int retval = -1; + struct mite_channel *channel = NULL; - // spin lock so mite_free_channel can be called safely from interrupts + // spin lock so mite_release_channel can be called safely from interrupts comedi_spin_lock_irqsave(&mite->lock, flags); - for(i = 0; i < mite->num_channels; ++i) + for(i = first_channel_to_try; i < mite->num_channels; ++i) { if(mite->channel_allocated[i] == 0) { mite->channel_allocated[i] = 1; - retval = i; + channel = &mite->channels[i]; + channel->ring = ring; break; } } comedi_spin_unlock_irqrestore(&mite->lock, flags); - return retval; + return channel; } -void mite_free_channel(struct mite_struct *mite, unsigned channel) +void mite_release_channel(struct mite_channel *mite_chan) { + struct mite_struct *mite = mite_chan->mite; unsigned long flags; - BUG_ON(channel >= mite->num_channels); - // spin lock to prevent races with mite_alloc_channel + // spin lock to prevent races with mite_request_channel comedi_spin_lock_irqsave(&mite->lock, flags); - mite->channel_allocated[channel] = 0; + mite->channel_allocated[mite_chan->channel] = 0; + mite_chan->ring = NULL; comedi_spin_unlock_irqrestore(&mite->lock, flags); } -void mite_dma_arm( struct mite_struct *mite, unsigned int channel ) +void mite_dma_arm(struct mite_channel *mite_chan) { + struct mite_struct *mite = mite_chan->mite; int chor; MDPRINTK("mite_dma_arm ch%i\n", channel); /* arm */ chor = CHOR_START; - writel(chor, mite->mite_io_addr + MITE_CHOR(channel)); + writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); // mite_dma_tcr(mite, channel); } /**************************************/ -int mite_load_buffer(struct mite_struct *mite, unsigned int channel, comedi_async *async) +int mite_buf_change(struct mite_dma_descriptor_ring *ring, comedi_async *async) { unsigned int n_links; int i; - struct mite_channel *mite_chan = &mite->channels[ channel ]; - - MDPRINTK("mite_load_buffer ch%i\n", channel); - if(mite_chan->ring){ - kfree(mite_chan->ring); - mite_chan->ring = NULL; + if(ring->descriptors){ + kfree(ring->descriptors); } + ring->descriptors = NULL; + ring->n_links = 0; if(async->prealloc_bufsz==0){ return 0; @@ -290,49 +299,39 @@ int mite_load_buffer(struct mite_struct *mite, unsigned int channel, comedi_asyn MDPRINTK("buf=%p buf(bus)=%08lx bufsz=0x%08x n_links=0x%04x\n", async->prealloc_buf, virt_to_bus(async->prealloc_buf), async->prealloc_bufsz, n_links); - mite_chan->ring = kmalloc(n_links * sizeof(struct mite_dma_chain), GFP_KERNEL); - if(!mite_chan->ring){ + ring->descriptors = kmalloc(n_links * sizeof(struct mite_dma_descriptor), GFP_KERNEL); + if(!ring->descriptors){ printk("mite: ring buffer allocation failed\n"); return -ENOMEM; } - mite_chan->n_links = n_links; - mite_chan->current_link = 0; - - for(i=0;iring[i].count = cpu_to_le32(PAGE_SIZE); - mite_chan->ring[i].addr = cpu_to_le32(virt_to_bus( - (void *)async->buf_page_list[i])); - mite_chan->ring[i].next = cpu_to_le32(virt_to_bus( - mite_chan->ring+i+1)); + ring->n_links = n_links; + + for(i = 0; i < n_links; i++){ + ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE); + ring->descriptors[i].addr = cpu_to_le32(virt_to_bus( + (void *)async->buf_page_list[i])); + ring->descriptors[i].next = cpu_to_le32(virt_to_bus( + ring->descriptors + i + 1)); } - - mite_chan->ring[n_links-1].next = cpu_to_le32(virt_to_bus( - mite_chan->ring)); - + ring->descriptors[n_links - 1].next = cpu_to_le32(virt_to_bus( + ring->descriptors)); + /* barrier is meant to insure that all the writes to the dma descriptors + have completed before the dma controller is commanded to read them */ + smp_wmb(); return 0; } -int mite_buf_change(struct mite_struct *mite, unsigned int channel, - comedi_async *async, unsigned long new_size) -{ - MDPRINTK("mite_buf_change ch%i\n", channel); - - mite_load_buffer(mite, channel, async); - - return 0; -} - -void mite_prep_dma( struct mite_struct *mite, unsigned int channel, +void mite_prep_dma(struct mite_channel *mite_chan, unsigned int num_device_bits, unsigned int num_memory_bits ) { unsigned int chor,chcr,mcr,dcr,lkcr; - struct mite_channel *mite_chan = &mite->channels[ channel ]; + struct mite_struct *mite = mite_chan->mite; - MDPRINTK("mite_prep_dma ch%i\n", channel ); + MDPRINTK("mite_prep_dma ch%i\n", mite_chan->channel); /* reset DMA and FIFO */ chor = CHOR_DMARESET | CHOR_FRESET; - writel(chor, mite->mite_io_addr + MITE_CHOR(channel)); + writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); /* short link chaining mode */ chcr = CHCR_SET_DMA_IE | CHCR_LINKSHORT | CHCR_SET_DONE_IE | CHCR_BURSTEN; @@ -355,7 +354,7 @@ void mite_prep_dma( struct mite_struct *mite, unsigned int channel, if(mite_chan->dir == COMEDI_INPUT){ chcr |= CHCR_DEV_TO_MEM; } - writel(chcr, mite->mite_io_addr + MITE_CHCR(channel)); + writel(chcr, mite->mite_io_addr + MITE_CHCR(mite_chan->channel)); /* to/from memory */ mcr = CR_RL(64) | CR_ASEQUP; @@ -373,11 +372,11 @@ void mite_prep_dma( struct mite_struct *mite, unsigned int channel, rt_printk( "mite: bug! invalid mem bit width for dma transfer\n" ); break; } - writel(mcr, mite->mite_io_addr + MITE_MCR(channel)); + writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel)); /* from/to device */ dcr = CR_RL(64) | CR_ASEQUP; - dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQSDRQ(channel); + dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQSDRQ(mite_chan->channel); switch( num_device_bits ){ case 8: dcr |= CR_PSIZE8; @@ -392,90 +391,94 @@ void mite_prep_dma( struct mite_struct *mite, unsigned int channel, rt_printk( "mite: bug! invalid dev bit width for dma transfer\n" ); break; } - writel(dcr, mite->mite_io_addr + MITE_DCR(channel)); + writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel)); /* reset the DAR */ - writel(0, mite->mite_io_addr + MITE_DAR(channel)); + writel(0, mite->mite_io_addr + MITE_DAR(mite_chan->channel)); /* the link is 32bits */ lkcr = CR_RL(64) | CR_ASEQUP | CR_PSIZE32; - writel(lkcr, mite->mite_io_addr + MITE_LKCR(channel)); + writel(lkcr, mite->mite_io_addr + MITE_LKCR(mite_chan->channel)); /* starting address for link chaining */ - writel(virt_to_bus(mite_chan->ring), - mite->mite_io_addr + MITE_LKAR(channel)); + writel(virt_to_bus(mite_chan->ring->descriptors), + mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); MDPRINTK("exit mite_prep_dma\n"); } -u32 mite_device_bytes_transferred(struct mite_struct *mite, unsigned int chan) +u32 mite_device_bytes_transferred(struct mite_channel *mite_chan) { - return readl(mite->mite_io_addr + MITE_DAR(chan)); + struct mite_struct *mite = mite_chan->mite; + return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel)); } -u32 mite_bytes_in_transit(struct mite_struct *mite, unsigned int chan) +u32 mite_bytes_in_transit(struct mite_channel *mite_chan) { - return readl(mite->mite_io_addr + MITE_FCR(chan)) & 0x000000FF; + struct mite_struct *mite = mite_chan->mite; + return readl(mite->mite_io_addr + MITE_FCR(mite_chan->channel)) & 0x000000FF; } // returns lower bound for number of bytes transferred from device to memory -u32 mite_bytes_written_to_memory_lb(struct mite_struct *mite, unsigned int chan) +u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan) { u32 device_byte_count; - device_byte_count = mite_device_bytes_transferred(mite, chan); - return device_byte_count - mite_bytes_in_transit(mite, chan); + device_byte_count = mite_device_bytes_transferred(mite_chan); + return device_byte_count - mite_bytes_in_transit(mite_chan); } // returns upper bound for number of bytes transferred from device to memory -u32 mite_bytes_written_to_memory_ub(struct mite_struct *mite, unsigned int chan) +u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan) { u32 in_transit_count; - in_transit_count = mite_bytes_in_transit(mite, chan); - return mite_device_bytes_transferred(mite, chan) - in_transit_count; + in_transit_count = mite_bytes_in_transit(mite_chan); + return mite_device_bytes_transferred(mite_chan) - in_transit_count; } // returns lower bound for number of bytes read from memory for transfer to device -u32 mite_bytes_read_from_memory_lb(struct mite_struct *mite, unsigned int chan) +u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan) { u32 device_byte_count; - device_byte_count = mite_device_bytes_transferred(mite, chan); - return device_byte_count + mite_bytes_in_transit(mite, chan); + device_byte_count = mite_device_bytes_transferred(mite_chan); + return device_byte_count + mite_bytes_in_transit(mite_chan); } // returns upper bound for number of bytes read from memory for transfer to device -u32 mite_bytes_read_from_memory_ub(struct mite_struct *mite, unsigned int chan) +u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan) { u32 in_transit_count; - in_transit_count = mite_bytes_in_transit(mite, chan); - return mite_device_bytes_transferred(mite, chan) + in_transit_count; + in_transit_count = mite_bytes_in_transit(mite_chan); + return mite_device_bytes_transferred(mite_chan) + in_transit_count; } -int mite_dma_tcr(struct mite_struct *mite, unsigned int channel) +unsigned mite_dma_tcr(struct mite_channel *mite_chan) { + struct mite_struct *mite = mite_chan->mite; int tcr; int lkar; - lkar = readl(mite->mite_io_addr + MITE_LKAR(channel)); - tcr = readl(mite->mite_io_addr + MITE_TCR(channel)); - MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", channel, lkar, tcr); + lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); + tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); + MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", mite_chan->channel, lkar, tcr); return tcr; } -void mite_dma_disarm(struct mite_struct *mite, unsigned int channel) +void mite_dma_disarm(struct mite_channel *mite_chan) { - int chor; + struct mite_struct *mite = mite_chan->mite; + unsigned chor; /* disarm */ chor = CHOR_ABORT; - writel(chor, mite->mite_io_addr + MITE_CHOR(channel)); + writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); } -int mite_sync_input_dma(struct mite_struct *mite, unsigned mite_channel, comedi_async *async) +int mite_sync_input_dma(struct mite_channel *mite_chan, comedi_async *async) { int count; unsigned int nbytes, old_alloc_count; @@ -485,8 +488,8 @@ int mite_sync_input_dma(struct mite_struct *mite, unsigned mite_channel, comedi_ // write alloc as much as we can comedi_buf_write_alloc(async, async->prealloc_bufsz); - nbytes = mite_bytes_written_to_memory_lb(mite, mite_channel); - if((int)(mite_bytes_written_to_memory_ub(mite, mite_channel) - old_alloc_count) > 0) + nbytes = mite_bytes_written_to_memory_lb(mite_chan); + if((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { rt_printk("mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; @@ -512,7 +515,7 @@ int mite_sync_input_dma(struct mite_struct *mite, unsigned mite_channel, comedi_ return 0; } -int mite_sync_output_dma(struct mite_struct *mite, unsigned mite_channel, comedi_async *async) +int mite_sync_output_dma(struct mite_channel *mite_chan, comedi_async *async) { int count; u32 nbytes_ub, nbytes_lb; @@ -522,11 +525,11 @@ int mite_sync_output_dma(struct mite_struct *mite, unsigned mite_channel, comedi old_alloc_count = async->buf_read_alloc_count; // read alloc as much as we can comedi_buf_read_alloc(async, async->prealloc_bufsz); - nbytes_lb = mite_bytes_read_from_memory_lb(mite, mite_channel); + nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan); if(async->cmd.stop_src == TRIG_COUNT && (int) (nbytes_lb - stop_count) > 0) nbytes_lb = stop_count; - nbytes_ub = mite_bytes_read_from_memory_ub(mite, mite_channel); + nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan); if(async->cmd.stop_src == TRIG_COUNT && (int) (nbytes_ub - stop_count) > 0) nbytes_ub = stop_count; @@ -621,14 +624,14 @@ static char *mite_CHSR_strings[] = { "28", "lpauses", "30", "int", }; -void mite_dump_regs(struct mite_struct *mite, int channel) +void mite_dump_regs(struct mite_channel *mite_chan) { - unsigned long mite_io_addr = (unsigned long) mite->mite_io_addr; + unsigned long mite_io_addr = (unsigned long) mite_chan->mite->mite_io_addr; unsigned long addr=0; unsigned long temp=0; - printk("mite_dump_regs ch%i\n", channel); - printk("mite address is =0x%08lx\n",mite_io_addr); + printk("mite_dump_regs ch%i\n", mite_chan->channel); + printk("mite address is =0x%08lx\n", mite_io_addr); addr = mite_io_addr+MITE_CHOR(channel); printk("mite status[CHOR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); @@ -704,8 +707,8 @@ EXPORT_SYMBOL(mite_setregs); #endif EXPORT_SYMBOL(mite_devices); EXPORT_SYMBOL(mite_list_devices); -EXPORT_SYMBOL(mite_alloc_channel); -EXPORT_SYMBOL(mite_free_channel); +EXPORT_SYMBOL(mite_offset_request_channel); +EXPORT_SYMBOL(mite_release_channel); EXPORT_SYMBOL(mite_prep_dma); EXPORT_SYMBOL(mite_buf_change); EXPORT_SYMBOL(mite_bytes_written_to_memory_lb); diff --git a/comedi/drivers/mite.h b/comedi/drivers/mite.h index 387376b1..089fffcf 100644 --- a/comedi/drivers/mite.h +++ b/comedi/drivers/mite.h @@ -41,21 +41,42 @@ #define MAX_MITE_DMA_CHANNELS 8 -struct mite_dma_chain{ +struct mite_dma_descriptor{ u32 count; u32 addr; u32 next; u32 dar; }; -struct mite_channel{ - int DMA_CheckNearEnd; - - int dir; - unsigned int current_link; +struct mite_dma_descriptor_ring +{ unsigned int n_links; + struct mite_dma_descriptor *descriptors; +}; + +static inline struct mite_dma_descriptor_ring* mite_alloc_ring(void) +{ + struct mite_dma_descriptor_ring *ring = kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL); + if(ring == NULL) return ring; + ring->n_links = 0; + ring->descriptors = NULL; + return ring; +}; + +static inline void mite_free_ring(struct mite_dma_descriptor_ring *ring) +{ + if(ring) + { + if(ring->descriptors) kfree(ring->descriptors); + kfree(ring); + } +}; - struct mite_dma_chain *ring; +struct mite_channel{ + struct mite_struct *mite; + unsigned channel; + int dir; + struct mite_dma_descriptor_ring *ring; }; struct mite_struct{ @@ -90,33 +111,38 @@ void mite_cleanup(void); int mite_setup(struct mite_struct *mite); void mite_unsetup(struct mite_struct *mite); void mite_list_devices(void); -int mite_alloc_channel(struct mite_struct *mite); -void mite_free_channel(struct mite_struct *mite, unsigned channel); - -int mite_dma_tcr(struct mite_struct *mite, unsigned int channel ); -void mite_dma_arm(struct mite_struct *mite, unsigned int channel ); -void mite_dma_disarm(struct mite_struct *mite, unsigned int channel ); -int mite_sync_input_dma(struct mite_struct *mite, unsigned mite_channel, comedi_async *async); -int mite_sync_output_dma(struct mite_struct *mite, unsigned mite_channel, comedi_async *async); -u32 mite_bytes_written_to_memory_lb(struct mite_struct *mite, unsigned int chan); -u32 mite_bytes_written_to_memory_ub(struct mite_struct *mite, unsigned int chan); -u32 mite_bytes_read_from_memory_lb(struct mite_struct *mite, unsigned int chan); -u32 mite_bytes_read_from_memory_ub(struct mite_struct *mite, unsigned int chan); -u32 mite_bytes_in_transit(struct mite_struct *mite, unsigned int chan); +struct mite_channel* mite_offset_request_channel(struct mite_struct *mite, struct mite_dma_descriptor_ring *ring, + unsigned first_channel_to_try); +static inline struct mite_channel* mite_request_channel( + struct mite_struct *mite, struct mite_dma_descriptor_ring *ring) +{ + return mite_offset_request_channel(mite, ring, 0); +} +void mite_release_channel(struct mite_channel *mite_chan); + +unsigned mite_dma_tcr(struct mite_channel *mite_chan ); +void mite_dma_arm(struct mite_channel *mite_chan ); +void mite_dma_disarm(struct mite_channel *mite_chan ); +int mite_sync_input_dma(struct mite_channel *mite_chan, comedi_async *async); +int mite_sync_output_dma(struct mite_channel *mite_chan, comedi_async *async); +u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan); +u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan); +u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan); +u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan); +u32 mite_bytes_in_transit(struct mite_channel *mite_chan); #if 0 unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,int len); void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan, int dir); #endif -void mite_prep_dma(struct mite_struct *mite, unsigned int channel, +void mite_prep_dma(struct mite_channel *mite_chan, unsigned int num_device_bits, unsigned int num_memory_bits ); -int mite_buf_change(struct mite_struct *mite, unsigned int channel, - comedi_async *async, unsigned long new_size); +int mite_buf_change(struct mite_dma_descriptor_ring *ring, comedi_async *async); #ifdef DEBUG_MITE void mite_print_chsr(unsigned int chsr); -void mite_dump_regs(struct mite_struct *mite, int channel); +void mite_dump_regs(struct mite_channel *mite_chan); #endif static inline int CHAN_OFFSET(int channel) @@ -378,5 +404,10 @@ enum CHSR_bits CHSR_DOERR = (3<<0), }; +static inline void mite_dma_reset(struct mite_channel *mite_chan) +{ + writel(CHOR_DMARESET | CHOR_FRESET, mite_chan->mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); +}; + #endif diff --git a/comedi/drivers/ni_660x.c b/comedi/drivers/ni_660x.c index 959ac3f1..af257ece 100644 --- a/comedi/drivers/ni_660x.c +++ b/comedi/drivers/ni_660x.c @@ -677,8 +677,7 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it) devpriv->counters[i].read_register = ni_gpct_read_register; devpriv->counters[i].variant = ni_gpct_variant_660x; devpriv->counters[i].clock_period_ps = 0; - devpriv->counters[i].mite = devpriv->mite; - devpriv->counters[i].mite_channel = -1; + devpriv->counters[i].mite_chan = NULL; }else { s->type = COMEDI_SUBD_UNUSED; diff --git a/comedi/drivers/ni_mio_common.c b/comedi/drivers/ni_mio_common.c index c5e81d1e..98e2b86b 100644 --- a/comedi/drivers/ni_mio_common.c +++ b/comedi/drivers/ni_mio_common.c @@ -309,7 +309,111 @@ static void get_last_sample_6143( comedi_device *dev ); #ifdef PCIDMA //static void mite_handle_interrupt(comedi_device *dev,unsigned int status); static int ni_ai_drain_dma(comedi_device *dev ); -#endif + +/* DMA channel setup */ +static inline void ni_set_ai_dma_channel(comedi_device *dev, int channel) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + devpriv->ai_ao_select_reg &= ~AI_DMA_Select_Mask; + /*FIXME this only works for channels 0,1,2. Need to reverse + engineer proper bits for higher mite channels with m-series */ + if(channel >= 0) + { + devpriv->ai_ao_select_reg |= (1 << (channel + AI_DMA_Select_Shift)) & AI_DMA_Select_Mask; + } + ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); + mmiowb(); + comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); +} + +static inline void ni_set_ao_dma_channel(comedi_device *dev, int channel) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + devpriv->ai_ao_select_reg &= ~AO_DMA_Select_Mask; + /*FIXME this only works for channels 0,1,2. Need to reverse + engineer proper bits for higher mite channels with m-series */ + if(channel >= 0) + { + devpriv->ai_ao_select_reg |= (1 << (channel + AO_DMA_Select_Shift)) & AO_DMA_Select_Mask; + } + ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); + mmiowb(); + comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); +} + +static int ni_request_ai_mite_channel(comedi_device *dev) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + BUG_ON(devpriv->ai_mite_chan); + devpriv->ai_mite_chan = mite_request_channel(devpriv->mite, devpriv->ai_mite_ring); + if(devpriv->ai_mite_chan == NULL) + { + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + comedi_error(dev, "failed to reserve mite dma channel for analog input."); + return -EBUSY; + } + ni_set_ai_dma_channel(dev, devpriv->ai_mite_chan->channel); + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + return 0; +} + +static int ni_request_ao_mite_channel(comedi_device *dev) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + BUG_ON(devpriv->ao_mite_chan); + devpriv->ao_mite_chan = mite_request_channel(devpriv->mite, devpriv->ao_mite_ring); + if(devpriv->ao_mite_chan == NULL) + { + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + comedi_error(dev, "failed to reserve mite dma channel for analog outut."); + return -EBUSY; + } + ni_set_ao_dma_channel(dev, devpriv->ao_mite_chan->channel); + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + return 0; +} + +#endif // PCIDMA + +static void ni_release_ai_mite_channel(comedi_device *dev) +{ +#ifdef PCIDMA + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if(devpriv->ai_mite_chan) + { + mite_release_channel(devpriv->ai_mite_chan); + devpriv->ai_mite_chan = NULL; + ni_set_ai_dma_channel(dev, -1); + } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif // PCIDMA +} + +static void ni_release_ao_mite_channel(comedi_device *dev) +{ +#ifdef PCIDMA + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if(devpriv->ao_mite_chan) + { + mite_release_channel(devpriv->ao_mite_chan); + devpriv->ao_mite_chan = NULL; + ni_set_ao_dma_channel(dev, -1); + } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif // PCIDMA +} static void ni_flush_ai_fifo(comedi_device *dev){ if(boardtype.reg_type == ni_reg_6143){ @@ -391,14 +495,13 @@ static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value) { unsigned long flags; - comedi_spin_lock_irqsave( &devpriv->window_lock, flags ); + comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); switch (reg){ case Interrupt_A_Enable_Register: if(value) devpriv->int_a_enable_reg |= bits; else devpriv->int_a_enable_reg &= ~bits; - comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags ); devpriv->stc_writew(dev, devpriv->int_a_enable_reg,Interrupt_A_Enable_Register); break; case Interrupt_B_Enable_Register: @@ -406,7 +509,6 @@ static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value) devpriv->int_b_enable_reg |= bits; else devpriv->int_b_enable_reg &= ~bits; - comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags ); devpriv->stc_writew(dev, devpriv->int_b_enable_reg,Interrupt_B_Enable_Register); break; case IO_Bidirection_Pin_Register: @@ -414,15 +516,14 @@ static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value) devpriv->io_bidirection_pin_reg |= bits; else devpriv->io_bidirection_pin_reg &= ~bits; - comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags ); devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register); break; default: rt_printk("Warning ni_set_bits() called with invalid arguments\n"); rt_printk("reg is %d\n",reg); - comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags ); break; } + comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags ); } @@ -431,8 +532,8 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) comedi_device *dev=d; unsigned short a_status; unsigned short b_status; - unsigned int m0_status; - unsigned int m1_status; + unsigned int ai_mite_status = 0; + unsigned int ao_mite_status = 0; unsigned long flags; #ifdef PCIDMA struct mite_struct *mite = devpriv->mite; @@ -444,26 +545,28 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) a_status=devpriv->stc_readw(dev, AI_Status_1_Register); b_status=devpriv->stc_readw(dev, AO_Status_1_Register); #ifdef PCIDMA - m0_status=readl(mite->mite_io_addr + MITE_CHSR(AI_DMA_CHAN)); - m1_status=readl(mite->mite_io_addr + MITE_CHSR(AO_DMA_CHAN)); -#else - m0_status = 0; - m1_status = 0; + if(devpriv->ai_mite_chan) + ai_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ai_mite_chan->channel)); + if(devpriv->ao_mite_chan) + ao_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ao_mite_chan->channel)); #endif - if(a_status&Interrupt_A_St || m0_status & CHSR_INT ) - handle_a_interrupt(dev, a_status, m0_status); - if(b_status&Interrupt_B_St || m1_status & CHSR_INT ) - handle_b_interrupt(dev, b_status, m1_status); + if(a_status & Interrupt_A_St || ai_mite_status & CHSR_INT ) + handle_a_interrupt(dev, a_status, ai_mite_status); + if(b_status & Interrupt_B_St || ao_mite_status & CHSR_INT ) + handle_b_interrupt(dev, b_status, ao_mite_status); comedi_spin_unlock_irqrestore(&dev->spinlock, flags); return IRQ_HANDLED; } #ifdef PCIDMA -static void ni_sync_ai_dma(struct mite_struct *mite, comedi_device *dev) +static void ni_sync_ai_dma(comedi_device *dev) { comedi_subdevice *s = dev->subdevices + 0; - int retval = mite_sync_input_dma(mite, AI_DMA_CHAN, s->async); + int retval; + + if(devpriv->ai_mite_chan == NULL) return; + retval = mite_sync_input_dma(devpriv->ai_mite_chan, s->async); if(retval < 0) { ni_ai_reset(dev,s); @@ -475,11 +578,12 @@ static void mite_handle_b_linkc(struct mite_struct *mite, comedi_device *dev) { comedi_subdevice *s = dev->subdevices + 1; - writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN)); + if(devpriv->ao_mite_chan == NULL) return; + writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel)); - if(mite_sync_output_dma(mite, AO_DMA_CHAN, s->async) < 0) + if(mite_sync_output_dma(devpriv->ao_mite_chan, s->async) < 0) { - ni_ao_reset(dev,s); + ni_ao_reset(dev, s); return; } } @@ -540,7 +644,7 @@ static void ni_handle_eos(comedi_device *dev, comedi_subdevice *s) for(i = 0; i < timeout; i++) { - ni_sync_ai_dma(devpriv->mite, dev); + ni_sync_ai_dma(dev); if((s->async->events & COMEDI_CB_EOS)) break; comedi_udelay(1); } @@ -562,7 +666,10 @@ static void shutdown_ai_command( comedi_device *dev ) #ifdef PCIDMA ni_ai_drain_dma( dev ); - mite_dma_disarm(devpriv->mite, AI_DMA_CHAN); + if(devpriv->ai_mite_chan) + { + mite_dma_disarm(devpriv->ai_mite_chan); + } #endif ni_handle_fifo_dregs(dev); get_last_sample_611x(dev); @@ -595,19 +702,19 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, #ifdef PCIDMA /* Currently, mite.c requires us to handle LINKC and DONE */ if(m_status & CHSR_LINKC){ - writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN)); - ni_sync_ai_dma(devpriv->mite, dev); + writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel)); + ni_sync_ai_dma(dev); } if(m_status & CHSR_DONE){ - writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN)); + writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel)); } if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){ rt_printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status); //mite_print_chsr(m_status); - mite_dma_disarm(devpriv->mite, AI_DMA_CHAN ); - writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN)); + mite_dma_disarm(devpriv->ai_mite_chan); + mite_dma_reset(devpriv->ai_mite_chan); //disable_irq(dev->irq); } #endif @@ -620,7 +727,7 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, * so it's a good idea to be careful. */ if(s->subdev_flags&SDF_RUNNING){ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - //comedi_event(dev,s,s->async->events); + comedi_event(dev,s,s->async->events); } return; } @@ -683,7 +790,6 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, } #endif if(ack) devpriv->stc_writew(dev, ack,Interrupt_A_Ack_Register); - comedi_event(dev,s,s->async->events); #ifdef DEBUG_INTERRUPT @@ -712,15 +818,15 @@ static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsig } if(m_status & CHSR_DONE){ - writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN)); + writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel)); } if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){ rt_printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status); //mite_print_chsr(m_status); - mite_dma_disarm(devpriv->mite, AO_DMA_CHAN ); - writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN)); - } + mite_dma_disarm(devpriv->ao_mite_chan); + mite_dma_reset(devpriv->ao_mite_chan); + } #endif if(b_status==0xffff)return; @@ -983,14 +1089,14 @@ static void ni_handle_fifo_half_full(comedi_device *dev) #ifdef PCIDMA static int ni_ai_drain_dma(comedi_device *dev ) { - struct mite_struct *mite = devpriv->mite; int i; static const int timeout = 10000; + if(devpriv->ai_mite_chan == NULL) return 0; for( i = 0; i < timeout; i++ ) { if((devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St) && - mite_bytes_in_transit(mite, AI_DMA_CHAN) == 0) + mite_bytes_in_transit(devpriv->ai_mite_chan) == 0) break; comedi_udelay(2); } @@ -998,11 +1104,11 @@ static int ni_ai_drain_dma(comedi_device *dev ) { rt_printk("ni_mio_common: wait for dma drain timed out\n"); rt_printk("mite_bytes_in_transit=%i, AI_Status1_Register=0x%x\n", - mite_bytes_in_transit(mite, AI_DMA_CHAN), devpriv->stc_readw(dev, AI_Status_1_Register)); + mite_bytes_in_transit(devpriv->ai_mite_chan), devpriv->stc_readw(dev, AI_Status_1_Register)); return -1; } - ni_sync_ai_dma( mite, dev ); + ni_sync_ai_dma(dev); return 0; } @@ -1124,39 +1230,45 @@ static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s, #ifdef PCIDMA -static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd) +static int ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd) { - struct mite_struct *mite = devpriv->mite; - struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ]; comedi_subdevice *s = dev->subdevices + 0; + int retval; + + retval = ni_request_ai_mite_channel(dev); + if(retval) return retval; + //rt_printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); /* write alloc the entire buffer */ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); - mite_chan->current_link = 0; - mite_chan->dir = COMEDI_INPUT; + devpriv->ai_mite_chan->dir = COMEDI_INPUT; switch(boardtype.reg_type) { case ni_reg_611x: case ni_reg_6143: - mite_prep_dma(mite, AI_DMA_CHAN, 32, 16); + mite_prep_dma(devpriv->ai_mite_chan, 32, 16); break; case ni_reg_628x: - mite_prep_dma(mite, AI_DMA_CHAN, 32, 32); + mite_prep_dma(devpriv->ai_mite_chan, 32, 32); break; default: - mite_prep_dma(mite, AI_DMA_CHAN, 16, 16); + mite_prep_dma(devpriv->ai_mite_chan, 16, 16); break; }; /*start the MITE*/ - mite_dma_arm(mite, AI_DMA_CHAN); + mite_dma_arm(devpriv->ai_mite_chan); + return 0; } -static void ni_ao_setup_MITE_dma(comedi_device *dev, comedi_cmd *cmd) +static int ni_ao_setup_MITE_dma(comedi_device *dev, comedi_cmd *cmd) { - struct mite_struct *mite = devpriv->mite; - struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ]; comedi_subdevice *s = dev->subdevices + 1; + int retval; + + retval = ni_request_ao_mite_channel(dev); + if(retval) return retval; + //rt_printk("comedi_debug: using mite channel %i for ao.\n", devpriv->ao_mite_chan->channel); /* read alloc the entire buffer */ comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); @@ -1165,19 +1277,19 @@ static void ni_ao_setup_MITE_dma(comedi_device *dev, comedi_cmd *cmd) to the mite's registers and arm it. */ smp_wmb(); - mite_chan->current_link = 0; - mite_chan->dir = COMEDI_OUTPUT; + devpriv->ao_mite_chan->dir = COMEDI_OUTPUT; if(boardtype.reg_type & (ni_reg_611x | ni_reg_6713)) { - mite_prep_dma(mite, AO_DMA_CHAN, 32, 32); + mite_prep_dma(devpriv->ao_mite_chan, 32, 32); }else { /* doing 32 instead of 16 bit wide transfers from memory makes the mite do 32 bit pci transfers, doubling pci bandwidth. */ - mite_prep_dma(mite, AO_DMA_CHAN, 16, 32); + mite_prep_dma(devpriv->ao_mite_chan, 16, 32); } /*start the MITE*/ - mite_dma_arm(mite, AO_DMA_CHAN); + mite_dma_arm(devpriv->ao_mite_chan); + return 0; } #endif // PCIDMA @@ -1191,7 +1303,10 @@ static void ni_ao_setup_MITE_dma(comedi_device *dev, comedi_cmd *cmd) static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s) { #ifdef PCIDMA - mite_dma_disarm(devpriv->mite, AI_DMA_CHAN); + if(devpriv->ai_mite_chan) + { + mite_dma_disarm(devpriv->ai_mite_chan); + } #endif /* ai configuration */ devpriv->stc_writew(dev, AI_Configuration_Start | AI_Reset, Joint_Reset_Register); @@ -1276,7 +1391,7 @@ static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s) #ifndef PCIDMA ni_handle_fifo_dregs(dev); #else - ni_sync_ai_dma(devpriv->mite, dev); + ni_sync_ai_dma(dev); #endif count = s->async->buf_write_count - s->async->buf_read_count; if(in_interrupt() == 0) @@ -1795,6 +1910,11 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) return 0; } +static void ni_ai_cmd_cleanup(comedi_device *dev, comedi_subdevice *s) +{ + ni_release_ai_mite_channel(dev); +} + static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) { comedi_cmd *cmd=&s->async->cmd; @@ -2053,7 +2173,10 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) } #ifdef PCIDMA - ni_ai_setup_MITE_dma(dev,cmd); + { + int retval = ni_ai_setup_MITE_dma(dev,cmd); + if(retval) return retval; + } //mite_dump_regs(devpriv->mite); #endif @@ -2428,7 +2551,7 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, int i; static const int timeout = 1000; - if(trignum!=0)return -EINVAL; + if(trignum!=0) return -EINVAL; ni_set_bits(dev, Interrupt_B_Enable_Register, AO_FIFO_Interrupt_Enable | AO_Error_Interrupt_Enable, 0); interrupt_b_bits = AO_Error_Interrupt_Enable; @@ -2436,7 +2559,8 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, devpriv->stc_writew(dev, 1, DAC_FIFO_Clear); if(boardtype.reg_type & ni_reg_6xxx_mask) ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x); - ni_ao_setup_MITE_dma(dev, &s->async->cmd); + ret = ni_ao_setup_MITE_dma(dev, &s->async->cmd); + if(ret) return ret; ret = ni_ao_wait_for_dma_load(dev); if(ret < 0) return ret; @@ -2476,6 +2600,11 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, return 0; } +static void ni_ao_cmd_cleanup(comedi_device *dev,comedi_subdevice *s) +{ + ni_release_ao_mite_channel(dev); +} + static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s) { comedi_cmd *cmd = &s->async->cmd; @@ -2726,8 +2855,11 @@ static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s) //ni_writew(devpriv->ao1p,AO_Configuration); #ifdef PCIDMA - mite_dma_disarm(devpriv->mite, AO_DMA_CHAN); - writel(CHOR_DMARESET | CHOR_FRESET, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN)); + if(devpriv->ao_mite_chan) + { + mite_dma_disarm(devpriv->ao_mite_chan); + mite_dma_reset(devpriv->ao_mite_chan); + } #endif devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register); @@ -3213,6 +3345,8 @@ static int ni_alloc_private(comedi_device *dev) if(ret < 0) return ret; spin_lock_init(&devpriv->window_lock); + spin_lock_init(&devpriv->soft_reg_copy_lock); + spin_lock_init(&devpriv->mite_channel_lock); return 0; }; @@ -3220,7 +3354,6 @@ static int ni_alloc_private(comedi_device *dev) static int ni_E_init(comedi_device *dev,comedi_devconfig *it) { comedi_subdevice *s; - int bits; unsigned j; if(boardtype.n_aochan > MAX_N_AO_CHAN) @@ -3249,13 +3382,14 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) s->len_chanlist=512; s->maxdata=(1<range_table=ni_range_lkup[boardtype.gainlkup]; - s->insn_read=ni_ai_insn_read; - s->insn_config=ni_ai_insn_config; - s->do_cmdtest=ni_ai_cmdtest; - s->do_cmd=ni_ai_cmd; - s->cancel=ni_ai_reset; - s->poll=ni_ai_poll; - s->munge=ni_ai_munge; + s->insn_read = &ni_ai_insn_read; + s->insn_config = &ni_ai_insn_config; + s->do_cmdtest = &ni_ai_cmdtest; + s->do_cmd = &ni_ai_cmd; + s->cmd_cleanup = &ni_ai_cmd_cleanup; + s->cancel = &ni_ai_reset; + s->poll = &ni_ai_poll; + s->munge = &ni_ai_munge; }else{ s->type=COMEDI_SUBD_UNUSED; } @@ -3284,8 +3418,9 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) #endif dev->write_subdev=s; s->subdev_flags |= SDF_CMD_WRITE; - s->do_cmd=ni_ao_cmd; - s->do_cmdtest=ni_ao_cmdtest; + s->do_cmd = &ni_ao_cmd; + s->cmd_cleanup = &ni_ao_cmd_cleanup; + s->do_cmdtest = &ni_ao_cmdtest; s->len_chanlist = boardtype.n_aochan; if((boardtype.reg_type & ni_reg_m_series_mask) == 0) s->munge=ni_ao_munge; @@ -3464,10 +3599,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) devpriv->counters[j].variant = ni_gpct_variant_e_series; } devpriv->counters[j].clock_period_ps = 0; -#ifdef PCIDMA - devpriv->counters[j].mite = devpriv->mite; -#endif - devpriv->counters[j].mite_channel = -1; + devpriv->counters[j].mite_chan = NULL; ni_tio_init_counter(&devpriv->counters[j]); } @@ -3506,15 +3638,8 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) } /* DMA setup */ - /* tell the STC which dma channels to use for AI and AO */ - bits = 1 << ( AI_DMA_CHAN ); - bits |= 1 << ( AO_DMA_CHAN + 4 ); - ni_writeb( bits, AI_AO_Select); - /* tell the STC which dma channels to use for - * General purpose counters 0 and 1 */ - bits = 1 << ( GPC0_DMA_CHAN ); - bits |= 1 << ( GPC1_DMA_CHAN + 4 ); - ni_writeb( bits, G0_G1_Select); + ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); + ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select); if(boardtype.reg_type & ni_reg_6xxx_mask) { diff --git a/comedi/drivers/ni_pcidio.c b/comedi/drivers/ni_pcidio.c index 93bbf840..f713afba 100644 --- a/comedi/drivers/ni_pcidio.c +++ b/comedi/drivers/ni_pcidio.c @@ -205,8 +205,17 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #define Interrupt_Control 75 /* bits same as flags */ -#define DMA_Line_Control 76 - #define DMAChannel(x) ((x)&0xf) +#define DMA_Line_Control_Group1 76 +#define DMA_Line_Control_Group2 108 +// channel zero is none +static inline unsigned primary_DMAChannel_bits(unsigned channel) +{ + return channel & 0x3; +} +static inline unsigned secondary_DMAChannel_bits(unsigned channel) +{ + return (channel << 2) & 0xc; +} #define Transfer_Size_Control 77 #define TransferWidth(x) ((x)&3) @@ -282,11 +291,6 @@ enum FPGA_Control_Bits #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -enum mite_dma_channels -{ - DI_DMA_CHAN = 1, -}; - static int nidio_attach(comedi_device *dev,comedi_devconfig *it); static int nidio_detach(comedi_device *dev); static comedi_driver driver_pcidio={ @@ -390,6 +394,9 @@ typedef struct{ int boardtype; int dio; unsigned short OpModeBits; + struct mite_channel *di_mite_chan; + struct mite_dma_descriptor_ring *di_mite_ring; + spinlock_t mite_channel_lock; }nidio96_private; #define devpriv ((nidio96_private *)dev->private) @@ -400,7 +407,7 @@ static int ni_pcidio_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trignum); static int nidio_find_device(comedi_device *dev,int bus,int slot); static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode); -static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s); +static int setup_mite_dma(comedi_device *dev,comedi_subdevice *s); #ifdef DEBUG_FLAGS static void ni_pcidio_print_flags(unsigned int flags); @@ -410,6 +417,43 @@ static void ni_pcidio_print_status(unsigned int status); #define ni_pcidio_print_status(x) #endif +static int ni_pcidio_request_di_mite_channel(comedi_device *dev) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + BUG_ON(devpriv->di_mite_chan); + devpriv->di_mite_chan = mite_offset_request_channel(devpriv->mite, devpriv->di_mite_ring, 1); + if(devpriv->di_mite_chan == NULL) + { + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + comedi_error(dev, "failed to reserve mite dma channel."); + return -EBUSY; + } + writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) | + secondary_DMAChannel_bits(devpriv->di_mite_chan->channel), + devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); + mmiowb(); + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + return 0; +} + +static void ni_pcidio_release_di_mite_channel(comedi_device *dev) +{ + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if(devpriv->di_mite_chan) + { + mite_release_channel(devpriv->di_mite_chan); + writeb(primary_DMAChannel_bits(0) | + secondary_DMAChannel_bits(0), + devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); + mmiowb(); + } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +} + static int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase) { if(dir){ @@ -420,13 +464,28 @@ static int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase) } } +static void nidio_disarm_and_reset_di_mite_channel(comedi_device *dev) +{ +#ifdef USE_DMA + unsigned long flags; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if(devpriv->di_mite_chan) + { + mite_dma_disarm(devpriv->di_mite_chan); + mite_dma_reset(devpriv->di_mite_chan); + } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif // USE_DMA +} + static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) { comedi_device *dev=d; comedi_subdevice *s = dev->subdevices; comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; - struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ]; + //int i, j; long int AuxData = 0; sampl_t data1 = 0; @@ -434,11 +493,11 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) int flags; int status; int work = 0; - unsigned int m_status; + unsigned int m_status = 0; + unsigned long irq_flags; status = readb(devpriv->mite->daq_io_addr+Interrupt_And_Window_Status); flags = readb(devpriv->mite->daq_io_addr+Group_1_Flags); - m_status = readl(mite->mite_io_addr + MITE_CHSR(DI_DMA_CHAN)); //interrupcions parasites if(dev->attached == 0){ @@ -446,48 +505,46 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA; } - DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x,m_status=0x%08x\n", - status,flags,m_status); + DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x\n", + status,flags); ni_pcidio_print_flags(flags); ni_pcidio_print_status(status); + + //printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); + //printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags); + if(devpriv->di_mite_chan) + m_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->di_mite_chan->channel)); #ifdef MITE_DEBUG mite_print_chsr(m_status); #endif //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN)); //mite_dump_regs(mite); - - //printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); - //printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); - if(m_status & CHSR_INT){ if(m_status & CHSR_LINKC){ - unsigned int count; - - writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(DI_DMA_CHAN)); - count = le32_to_cpu(mite_chan->ring[mite_chan->current_link].count); - - /* XXX need to byteswap */ - - async->buf_write_count += count; - async->buf_write_ptr += count; - if(async->buf_write_ptr >= async->prealloc_bufsz){ - async->buf_write_ptr -= async->prealloc_bufsz; - } - mite_chan->current_link++; - if(mite_chan->current_link >= mite_chan->n_links){ - mite_chan->current_link=0; + int retval; + + writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->di_mite_chan->channel)); + retval = mite_sync_input_dma(devpriv->di_mite_chan, s->async); + if(retval) + { + mite_dma_disarm(devpriv->di_mite_chan); + mite_dma_reset(devpriv->di_mite_chan); } + /* XXX need to byteswap */ } if(m_status & CHSR_DONE){ - writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR(DI_DMA_CHAN)); + writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR(devpriv->di_mite_chan->channel)); } if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1 | CHSR_MRDY)){ DPRINTK("unknown mite interrupt, disabling IRQ\n"); - writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR(DI_DMA_CHAN)); + mite_dma_disarm(devpriv->di_mite_chan); + mite_dma_reset(devpriv->di_mite_chan); disable_irq(dev->irq); } - async->events |= COMEDI_CB_BLOCK; } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags); while(status&DataLeft){ work++; @@ -530,20 +587,14 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) writeb(0x00,devpriv->mite->daq_io_addr+OpMode); writeb(0x00,devpriv->mite->daq_io_addr+Master_DMA_And_Interrupt_Control); -#ifdef USE_DMA - mite_dma_disarm(mite, DI_DMA_CHAN); - writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR(DI_DMA_CHAN)); -#endif + nidio_disarm_and_reset_di_mite_channel(dev); break; }else if(flags & Waited){ DPRINTK("Waited\n"); writeb(ClearWaited,devpriv->mite->daq_io_addr+Group_1_First_Clear); writeb(0x00,devpriv->mite->daq_io_addr+Master_DMA_And_Interrupt_Control); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; -#ifdef USE_DMA - mite_dma_disarm(mite, DI_DMA_CHAN); - writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR(DI_DMA_CHAN)); -#endif + nidio_disarm_and_reset_di_mite_channel(dev); break; }else if(flags & PrimaryTC){ DPRINTK("PrimaryTC\n"); @@ -573,7 +624,6 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) out: comedi_event(dev,s,async->events); - #if 0 if(!tag){ writeb(0x03,devpriv->mite->daq_io_addr+Master_DMA_And_Interrupt_Control); @@ -807,6 +857,10 @@ static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode) return divider; } +static void ni_pcidio_cmd_cleanup(comedi_device *dev,comedi_subdevice *s) +{ + ni_pcidio_release_di_mite_channel(dev); +} static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s) { @@ -876,13 +930,17 @@ static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s) } #ifdef USE_DMA - writeb(0x05,devpriv->mite->daq_io_addr+DMA_Line_Control); - writeb(0x30,devpriv->mite->daq_io_addr+Group_1_First_Clear); + writeb(ClearPrimaryTC | ClearSecondaryTC, + devpriv->mite->daq_io_addr + Group_1_First_Clear); - setup_mite_dma(dev,s); + { + int retval = setup_mite_dma(dev,s); + if(retval) return retval; + } #else - writeb(0x00,devpriv->mite->daq_io_addr+DMA_Line_Control); + writeb(0x00, devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); #endif + writeb(0x00, devpriv->mite->daq_io_addr + DMA_Line_Control_Group2); /* clear and enable interrupts */ writeb(0xff,devpriv->mite->daq_io_addr+Group_1_First_Clear); @@ -909,19 +967,19 @@ static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s) return 0; } - -static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s) +static int setup_mite_dma(comedi_device *dev,comedi_subdevice *s) { - struct mite_struct *mite = devpriv->mite; - struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ]; + int retval; - mite_chan->current_link = 0; + retval = ni_pcidio_request_di_mite_channel(dev); + if(retval) return retval; - mite_chan->dir = COMEDI_INPUT; + devpriv->di_mite_chan->dir = COMEDI_INPUT; - mite_prep_dma(mite, DI_DMA_CHAN, 32, 32); + mite_prep_dma(devpriv->di_mite_chan, 32, 32); - mite_dma_arm(mite, DI_DMA_CHAN); + mite_dma_arm(devpriv->di_mite_chan); + return 0; } @@ -950,7 +1008,7 @@ static int ni_pcidio_change(comedi_device *dev, comedi_subdevice *s, { int ret; - ret = mite_buf_change(devpriv->mite, DI_DMA_CHAN, s->async, new_size); + ret = mite_buf_change(devpriv->di_mite_ring, s->async); if(ret<0)return ret; memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz); @@ -1070,6 +1128,9 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it) if((ret=alloc_private(dev,sizeof(nidio96_private)))<0) return ret; + devpriv->di_mite_ring = mite_alloc_ring(); + if(devpriv->di_mite_ring == NULL) return -ENOMEM; + spin_lock_init(&devpriv->mite_channel_lock); ret=nidio_find_device(dev,it->options[0],it->options[1]); if(ret<0)return ret; @@ -1118,6 +1179,7 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it) s->insn_config = ni_pcidio_insn_config; s->insn_bits = ni_pcidio_insn_bits; s->do_cmd = ni_pcidio_cmd; + s->cmd_cleanup = ni_pcidio_cmd_cleanup; s->do_cmdtest = ni_pcidio_cmdtest; s->cancel = ni_pcidio_cancel; s->len_chanlist=32; /* XXX */ @@ -1155,9 +1217,16 @@ static int nidio_detach(comedi_device *dev) if(dev->irq) comedi_free_irq(dev->irq,dev); - if(devpriv && devpriv->mite) - mite_unsetup(devpriv->mite); - + if(devpriv) + { + if(devpriv->di_mite_ring) + { + mite_free_ring(devpriv->di_mite_ring); + devpriv->di_mite_ring = NULL; + } + if(devpriv->mite) + mite_unsetup(devpriv->mite); + } return 0; } diff --git a/comedi/drivers/ni_pcimio.c b/comedi/drivers/ni_pcimio.c index 361843da..3e873204 100644 --- a/comedi/drivers/ni_pcimio.c +++ b/comedi/drivers/ni_pcimio.c @@ -1041,6 +1041,12 @@ COMEDI_INITCLEANUP(driver_pcimio); typedef struct{ struct mite_struct *mite; + struct mite_channel *ai_mite_chan; + struct mite_channel *ao_mite_chan; + struct mite_channel *gpct_mite_chan[2]; + struct mite_dma_descriptor_ring *ai_mite_ring; + struct mite_dma_descriptor_ring *ao_mite_ring; + struct mite_dma_descriptor_ring *gpct_mite_ring[2]; NI_PRIVATE_COMMON }ni_private; @@ -1407,12 +1413,17 @@ static void init_6143(comedi_device *dev) static int pcimio_detach(comedi_device *dev) { mio_common_detach(dev); - - if(dev->private && devpriv->mite) - mite_unsetup(devpriv->mite); - if(dev->irq){ - comedi_free_irq(dev->irq,dev); + comedi_free_irq(dev->irq, dev); + } + if(dev->private) + { + mite_free_ring(devpriv->ai_mite_ring); + mite_free_ring(devpriv->ao_mite_ring); + mite_free_ring(devpriv->gpct_mite_ring[0]); + mite_free_ring(devpriv->gpct_mite_ring[1]); + if(devpriv->mite) + mite_unsetup(devpriv->mite); } return 0; @@ -1426,6 +1437,14 @@ static int pcimio_attach(comedi_device *dev,comedi_devconfig *it) ret=ni_alloc_private(dev); if(ret<0)return ret; + devpriv->ai_mite_ring = mite_alloc_ring(); + if(devpriv->ai_mite_ring == NULL) return -ENOMEM; + devpriv->ao_mite_ring = mite_alloc_ring(); + if(devpriv->ao_mite_ring == NULL) return -ENOMEM; + devpriv->gpct_mite_ring[0] = mite_alloc_ring(); + if(devpriv->gpct_mite_ring[0] == NULL) return -ENOMEM; + devpriv->gpct_mite_ring[1] = mite_alloc_ring(); + if(devpriv->gpct_mite_ring[1] == NULL) return -ENOMEM; ret=pcimio_find_device(dev,it->options[0],it->options[1]); if(ret<0)return ret; @@ -1513,8 +1532,8 @@ static int pcimio_ai_change(comedi_device *dev, comedi_subdevice *s, { int ret; - ret = mite_buf_change(devpriv->mite, AI_DMA_CHAN, s->async, new_size); - if(ret<0)return ret; + ret = mite_buf_change(devpriv->ai_mite_ring, s->async); + if(ret < 0) return ret; return 0; } @@ -1524,8 +1543,8 @@ static int pcimio_ao_change(comedi_device *dev, comedi_subdevice *s, { int ret; - ret = mite_buf_change(devpriv->mite, AO_DMA_CHAN, s->async, new_size); - if(ret<0)return ret; + ret = mite_buf_change(devpriv->ao_mite_ring, s->async); + if(ret < 0) return ret; return 0; } diff --git a/comedi/drivers/ni_stc.h b/comedi/drivers/ni_stc.h index 04b1eb13..6390c384 100644 --- a/comedi/drivers/ni_stc.h +++ b/comedi/drivers/ni_stc.h @@ -691,6 +691,13 @@ enum XXX_Status_Bits #define Channel_B_Mode 0x05 #define Channel_C_Mode 0x07 #define AI_AO_Select 0x09 +enum AI_AO_Select_Bits +{ + AI_DMA_Select_Shift = 0, + AI_DMA_Select_Mask = 0xf, + AO_DMA_Select_Shift = 4, + AO_DMA_Select_Mask = 0xf << AO_DMA_Select_Shift +}; #define G0_G1_Select 0x0b /* 16 bit registers */ @@ -855,14 +862,6 @@ enum cs5529_status_bits but I thought I'd put it here anyway. */ -/* our default usage of mite channels */ -enum mite_dma_channel{ - AI_DMA_CHAN = 0, - AO_DMA_CHAN = 1, - GPC0_DMA_CHAN = 2, - GPC1_DMA_CHAN = 3, -}; - enum{ ai_gain_16=0, ai_gain_8, ai_gain_14, ai_gain_4, ai_gain_611x, ai_gain_622x, ai_gain_628x, ai_gain_6143}; enum caldac_enum { caldac_none=0, mb88341, dac8800, dac8043, ad8522, ad8804, ad8842, ad8804_debug }; @@ -1292,6 +1291,8 @@ static ni_board ni_boards[]; unsigned int ai_calib_source; \ unsigned int ai_calib_source_enabled; \ spinlock_t window_lock; \ + spinlock_t soft_reg_copy_lock; \ + spinlock_t mite_channel_lock; \ \ int changain_state; \ unsigned int changain_spec; \ @@ -1300,7 +1301,7 @@ static ni_board ni_boards[]; unsigned short ao[MAX_N_AO_CHAN]; \ unsigned short caldacs[MAX_N_CALDACS]; \ \ - volatile unsigned short ai_cmd2; \ + unsigned short ai_cmd2; \ \ unsigned short ao_conf[MAX_N_AO_CHAN]; \ unsigned short ao_mode1; \ @@ -1321,13 +1322,15 @@ static ni_board ni_boards[]; unsigned short clock_and_fout; \ unsigned short clock_and_fout2; \ \ - volatile unsigned short int_a_enable_reg; \ - volatile unsigned short int_b_enable_reg; \ + unsigned short int_a_enable_reg; \ + unsigned short int_b_enable_reg; \ unsigned short io_bidirection_pin_reg; \ unsigned short rtsi_trig_direction_reg; \ unsigned short rtsi_trig_a_output_reg; \ unsigned short rtsi_trig_b_output_reg; \ unsigned short pfi_output_select_reg[NUM_PFI_OUTPUT_SELECT_REGS]; \ + unsigned short ai_ao_select_reg; \ + unsigned short g0_g1_select_reg; \ \ unsigned clock_ns; \ unsigned clock_source; \ diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c index 3c9f851f..32632237 100644 --- a/comedi/drivers/ni_tio.c +++ b/comedi/drivers/ni_tio.c @@ -1978,21 +1978,19 @@ int ni_tio_winsn(struct ni_gpct *counter, static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async) { comedi_cmd *cmd = &async->cmd; - struct mite_channel *mite_chan = &counter->mite->channels[counter->mite_channel]; /* write alloc the entire buffer */ comedi_buf_write_alloc(async, async->prealloc_bufsz); - mite_chan->current_link = 0; - mite_chan->dir = COMEDI_INPUT; - mite_prep_dma(counter->mite, counter->mite_channel, 32, 32); + counter->mite_chan->dir = COMEDI_INPUT; + mite_prep_dma(counter->mite_chan, 32, 32); if(counter->variant == ni_gpct_variant_m_series || counter->variant == ni_gpct_variant_660x) { counter->write_register(counter, Gi_DMA_Enable_Bit, NITIO_Gi_DMA_Config_Reg(counter->counter_index)); } /*start the MITE*/ - mite_dma_arm(counter->mite, counter->mite_channel); + mite_dma_arm(counter->mite_chan); return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } @@ -2005,7 +2003,7 @@ int ni_tio_cmd(struct ni_gpct *counter, comedi_async *async) { comedi_cmd *cmd = &async->cmd; - if(counter->mite == NULL || counter->mite_channel < 0) + if(counter->mite_chan == NULL) { rt_printk("ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n"); return -EIO; @@ -2027,8 +2025,8 @@ int ni_tio_cmdtest(struct ni_gpct *counter) int ni_tio_cancel(struct ni_gpct *counter) { - if(counter->mite == NULL || counter->mite_channel < 0) return 0; - mite_dma_disarm(counter->mite, counter->mite_channel); + if(counter->mite_chan == NULL) return 0; + mite_dma_disarm(counter->mite_chan); return 0; } diff --git a/comedi/drivers/ni_tio.h b/comedi/drivers/ni_tio.h index 2bb50312..e561088a 100644 --- a/comedi/drivers/ni_tio.h +++ b/comedi/drivers/ni_tio.h @@ -106,8 +106,7 @@ struct ni_gpct unsigned (*read_register)(struct ni_gpct *this, enum ni_gpct_register reg); enum ni_gpct_variant variant; uint64_t clock_period_ps; /* clock period in picoseconds */ - struct mite_struct *mite; - int mite_channel; /* -1 when no channel is allocated to the counter */ + struct mite_channel *mite_chan; unsigned regs[MAX_NUM_NITIO_REGS]; };