From baefdc976c6d60ac414e938c439781fbb0ae1f3f Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 6 Apr 2001 22:55:53 +0000 Subject: [PATCH] Mite additions from Tim Ousley --- comedi/drivers/mite.c | 235 ++++++++++++++++++++++++++++++++++++++++-- comedi/drivers/mite.h | 23 ++++- 2 files changed, 244 insertions(+), 14 deletions(-) diff --git a/comedi/drivers/mite.c b/comedi/drivers/mite.c index 76fd59b4..00a1145e 100644 --- a/comedi/drivers/mite.c +++ b/comedi/drivers/mite.c @@ -69,9 +69,9 @@ struct mite_struct *mite_devices = NULL; - - - + +#define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK))) +#define min(a,b) (((a)<(b))?(a):(b)) #ifdef PCI_SUPPORT_VER1 /* routines for the old PCI code (before 2.1.55) */ @@ -92,6 +92,10 @@ void mite_init(void) pcibios_read_config_word(pci_bus,pci_device_fn,PCI_VENDOR_ID,&vendor); if(vendor==PCI_VENDOR_ID_NATINST){ mite=kmalloc(sizeof(*mite),GFP_KERNEL); + if(!mite){ + printk("mite: allocation failed\n"); + return; + } memset(mite,0,sizeof(*mite)); mite->pci_bus=pci_bus; @@ -118,6 +122,10 @@ void mite_init(void) pci_for_each_dev(pcidev){ if(pcidev->vendor==PCI_VENDOR_ID_NATINST){ mite=kmalloc(sizeof(*mite),GFP_KERNEL); + if(!mite){ + printk("mite: allocation failed\n"); + return; + } memset(mite,0,sizeof(*mite)); mite->pcidev=pcidev; @@ -165,8 +173,9 @@ int mite_setup(struct mite_struct *mite) printk("DAQ:0x%08lx mapped to %p, ",mite->daq_phys_addr,mite->daq_io_addr); /* XXX don't know what the 0xc0 and 0x80 mean */ + /* It must be here for the driver to work though */ writel(mite->daq_phys_addr | 0x80 , mite->mite_io_addr + 0xc0 ); - + #ifdef PCI_SUPPORT_VER1 { unsigned char irq; @@ -178,10 +187,9 @@ int mite_setup(struct mite_struct *mite) /* DMA setup */ for(i=0;iring[i].next=virt_to_bus(mite->ring+i+1); - mite->ring[i].unused=0x1c; /* eh? */ + } mite->ring[i].next=0; - mite->ring[i].unused=0x1c; /* eh? */ mite->used = 1; @@ -261,8 +269,8 @@ void mite_dma_prep(struct mite_struct *mite,comedi_subdevice *s) chor = CHOR_DMARESET | CHOR_FRESET; writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0)); - chcr = CHCR_LINKLONG | CHCR_DEV_TO_MEM; - //chcr = CHCR_LINKLONG | CHCR_MEM_TO_DEV; + // Should this be LINKLONG for 32HS? + chcr = CHCR_LINKSHORT | CHCR_DEV_TO_MEM; writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(0)); mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF; @@ -276,7 +284,105 @@ void mite_dma_prep(struct mite_struct *mite,comedi_subdevice *s) writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(0)); writel(virt_to_bus(mite->ring),mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(0)); +} + + +/* + * Create the short linkchaining MITE linked list using kernel memory + * a drop in replacement for mite_ll_from_user( ) + */ +unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,int len) +{ + int i,size_so_far; + unsigned long nup; + //unsigned long prealloc_buf,prealloc_bufsz; + //comedi_subdevice *s; + //struct mite_struct *mite=NULL; + //comedi_async *async=NULL; + //int len; + + MDPRINTK("mite_ll_from_kvmem\n"); + //s=dev->subdevices+cmd->subdev; + //mite=devpriv->mite; + //prealloc_buf=(unsigned long)s->async->prealloc_buf; + //prealloc_bufsz=s->async->prealloc_bufsz; + + //len = min(cmd->scan_end_arg*cmd->stop_arg*sizeof(sampl_t), async->data_len); + if(async->data_lenComedi Error: preallocated DMA buffer is too small to hold the samples."); + } + //find the kernel's memory pages. + nup = (unsigned long)async->data; + i=0; + size_so_far=0; + MDPRINTK("buf=0x%08lx bufsz=0x%08x\n", + (unsigned long)prealloc_buf,prealloc_bufsz); + + while(((void*)nup < (async->data+len))&&(i<(MITE_RING_SIZE-1))) { + mite->ring[i].addr =kvirt_to_bus(nup);// it's already a kernel address :-) + mite->ring[i].count=min(1+TOP_OF_PAGE(nup)-nup,len-size_so_far); + mite->ring[i].next=virt_to_bus(mite->ring+i+1); + size_so_far += mite->ring[i].count; + nup += mite->ring[i].count; + i++; + } + mite->ring[i].count=0; + MDPRINTK("i was %d, size_so_far was %d\n",i,size_so_far); + if(size_so_farComedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n"); + } + #if 0 //#ifdef DEBUG_MITE + for(i=0; iring[i].addr, + mite->ring[i].next, mite->ring[i].count); + } + #endif + MDPRINTK("exit mite_ll_from_kvmem\n"); + return virt_to_bus(&(mite->ring[0])); +} + +unsigned long mite_ll_from_user(comedi_device *dev, comedi_cmd *cmd) +{ + int i,size_so_far,len; + unsigned long nup; + + comedi_subdevice *s; + struct mite_struct *mite; + + MDPRINTK("mite_ll_from_user\n"); + s=dev->subdevices+cmd->subdev; + //mite=devpriv->mite; + len = cmd->data_len; + + //find the users memory pages. + nup = (unsigned long)cmd->data; i=0; size_so_far=0; + MDPRINTK("buf=0x%08lx bufsz=0x%08x\n", + (unsigned long)cmd->data,cmd->data_len); + while(((void*)nup < ((void*)cmd->data+len))&&(i<(MITE_RING_SIZE-1))) { + mite->ring[i].addr =uvirt_to_bus(nup); + mite->ring[i].count=min(1+TOP_OF_PAGE(nup)-nup,len-size_so_far); + mite->ring[i].next=virt_to_bus(mite->ring+i+1); + size_so_far += mite->ring[i].count; + nup += mite->ring[i].count; + i++; + } + mite->ring[i].count=0; + MDPRINTK("i was %d, size_so_far was %d\n",i,size_so_far); + if(size_so_farComedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n"); + printk("<1>Comedi Error: MITE_RING_SIZE is %d, buffer is %d bytes\n", + MITE_RING_SIZE, len); + } + + #if 0 //#ifdef DEBUG_MITE + for(i=0; iring[i].addr, + mite->ring[i].next, mite->ring[i].count); + } + #endif + MDPRINTK("exit mite_ll_from_user\n"); + return virt_to_bus(&(mite->ring[0])); } void mite_dma_arm(struct mite_struct *mite) @@ -290,6 +396,67 @@ void mite_dma_arm(struct mite_struct *mite) mite_dma_tcr(mite); } + +void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan,int dir) +{ + //*mite is the mite to work with + //ll_start is the beginning of the linkshort mite linked list + //chan is the DMA channel to use on the MITE (0,1,2,3) + //dir is the direction of the transfer COMEDI_INPUT or COMEDI_OUTPUT + int chor,chcr,mcr,dcr,lkcr; + + MDPRINTK("mite_setregs\n"); + + chor = CHOR_DMARESET | CHOR_FRESET; //reset DMA and FIFO + writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(chan)); + + //short link chaining mode + chcr = CHCR_SET_DMA_IE| CHCR_LINKSHORT | CHCR_SET_DONE_IE; + /*Link Complete Interrupt: interrupt every time a link in MITE_RING + is completed. This can generate a lot of extra interrupts, but right now we + update the values of buf_int_ptr and buf_int_count at each interrupt. A + better method is to poll the MITE before each user "read()" to calculate the + number of bytes available. mite_bytes_transferred() is provided to get the + number of bytes transferred to system memory so far. + */ + chcr |= CHCR_SET_LC_IE; + + if(dir == COMEDI_INPUT){ + chcr |= CHCR_DEV_TO_MEM; + } + writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(chan)); + + //16 bits, to memory + mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF; + writel(mcr,mite->mite_io_addr+MITE_MCR+CHAN_OFFSET(chan)); + + //16 bits, from STC + dcr = CR_RL64 | CR_ASEQx(1) | CR_PSIZEHALF; + dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQS(0x4+chan); + writel(dcr,mite->mite_io_addr+MITE_DCR+CHAN_OFFSET(chan)); + + //reset the DAR + writel(0,mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan)); + + //the link is 32bits + lkcr = CR_RL64 | CR_ASEQUP | CR_PSIZEWORD; + writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(chan)); + + //starting address for link chaining + writel(ll_start,mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(chan)); + + MDPRINTK("exit mite_setregs\n"); +} + +int mite_bytes_transferred(struct mite_struct *mite, int chan) +{ + int bytes; + + bytes = readl(mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan)); + bytes -= readl(mite->mite_io_addr+MITE_FCR+CHAN_OFFSET(chan)) & 0x000000FF; + return bytes; +} + int mite_dma_tcr(struct mite_struct *mite) { int tcr; @@ -297,7 +464,7 @@ int mite_dma_tcr(struct mite_struct *mite) lkar=readl(mite->mite_io_addr+CHAN_OFFSET(0)+MITE_LKAR); tcr=readl(mite->mite_io_addr+CHAN_OFFSET(0)+MITE_TCR); - printk("lkar=0x%08x tcr=%d\n",lkar,tcr); + MDPRINTK("lkar=0x%08x tcr=%d\n",lkar,tcr); return tcr; } @@ -311,6 +478,49 @@ void mite_dma_disarm(struct mite_struct *mite) writel(chor,mite->mite_io_addr+CHAN_OFFSET(0)+MITE_CHOR); } +void mite_dump_regs(struct mite_struct *mite) +{ + unsigned long mite_io_addr = mite->mite_io_addr; + unsigned long addr=0; + unsigned long temp=0; + + printk("mite address is =0x%08lx\n",mite_io_addr); + + addr = mite_io_addr+MITE_CHOR+CHAN_OFFSET(0); + printk("mite status[CHOR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_CHOR_strings,temp); + addr = mite_io_addr+MITE_CHCR+CHAN_OFFSET(0); + printk("mite status[CHCR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_CHCR_strings,temp); + addr = mite_io_addr+MITE_TCR+CHAN_OFFSET(0); + printk("mite status[TCR] at 0x%08lx =0x%08x\n",addr, readl(addr)); + addr = mite_io_addr+MITE_MCR+CHAN_OFFSET(0); + printk("mite status[MCR] at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_MCR_strings,temp); + + addr = mite_io_addr+MITE_MAR+CHAN_OFFSET(0); + printk("mite status[MAR] at 0x%08lx =0x%08x\n",addr, readl(addr)); + addr = mite_io_addr+MITE_DCR+CHAN_OFFSET(0); + printk("mite status[DCR] at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_CR_strings,temp); + addr = mite_io_addr+MITE_DAR+CHAN_OFFSET(0); + printk("mite status[DAR] at 0x%08lx =0x%08x\n",addr, readl(addr)); + addr = mite_io_addr+MITE_LKCR+CHAN_OFFSET(0); + printk("mite status[LKCR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_CR_strings,temp); + addr = mite_io_addr+MITE_LKAR+CHAN_OFFSET(0); + printk("mite status[LKAR]at 0x%08lx =0x%08x\n",addr, readl(addr)); + + addr = mite_io_addr+MITE_CHSR+CHAN_OFFSET(0); + printk("mite status[CHSR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr)); + //mite_decode(mite_CHSR_strings,temp); + addr = mite_io_addr+MITE_FCR+CHAN_OFFSET(0); + printk("mite status[FCR] at 0x%08lx =0x%08x\n\n",addr, readl(addr)); +} + + + + #ifdef MODULE int init_module(void) { @@ -354,6 +564,13 @@ EXPORT_SYMBOL(mite_kvmem_segment_load); EXPORT_SYMBOL(mite_devices); EXPORT_SYMBOL(mite_list_devices); +//Tim's debugging function +EXPORT_SYMBOL(mite_dump_regs); +EXPORT_SYMBOL(mite_ll_from_user); +EXPORT_SYMBOL(mite_ll_from_kvmem); +EXPORT_SYMBOL(mite_setregs); +EXPORT_SYMBOL(mite_bytes_transferred); + #endif #endif diff --git a/comedi/drivers/mite.h b/comedi/drivers/mite.h index e1830560..5383638a 100644 --- a/comedi/drivers/mite.h +++ b/comedi/drivers/mite.h @@ -33,13 +33,19 @@ #define PCI_VENDOR_ID_NATINST 0x1093 +//#define DEBUG_MITE -#define MITE_RING_SIZE 32 +#ifdef DEBUG_MITE +#define MDPRINTK(format,args...) printk(format , ## args ) +#else +#define MDPRINTK(format,args...) +#endif + +#define MITE_RING_SIZE 3000 struct mite_dma_chain{ u32 count; u32 addr; - u32 unused; u32 next; }; @@ -88,7 +94,12 @@ int mite_dma_tcr(struct mite_struct *mite); void mite_dma_arm(struct mite_struct *mite); void mite_dma_disarm(struct mite_struct *mite); - + +unsigned long mite_ll_from_user(comedi_device *dev, comedi_cmd *cmd); +unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,int len); +void mite_dump_regs(struct mite_struct *mite); +void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan, int dir); +int mite_bytes_transferred(struct mite_struct *mite, int chan); #define CHAN_OFFSET(x) (0x100*(x)) @@ -206,6 +217,10 @@ void mite_dma_disarm(struct mite_struct *mite); #define CR_PORTMXI (3<<6) #define CR_AMDEVICE (1<<0) +#define CHSR_INT 0x80000000 +#define CHSR_DONE 0x02000000 +#define CHSR_LINKC 0x00080000 + #define MITE_MCR 0x50c #define MCRPON 0 @@ -241,7 +256,5 @@ void mite_dma_disarm(struct mite_struct *mite); #define MITE_AMHOST_A32D64_BLOCK 0x08 #define MITE_AMHOST_A24_BLOCK 0x3b - - #endif -- 2.26.2