more pci-dma stuff, still nonfunctional
authorFrank Mori Hess <fmhess@speakeasy.net>
Tue, 18 Sep 2001 23:23:36 +0000 (23:23 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Tue, 18 Sep 2001 23:23:36 +0000 (23:23 +0000)
comedi/drivers/cb_pcidas64.c
comedi/drivers/plx9080.h

index cebd3020645318efb39fcefa98d9360137a23538..4d8c74ed973666c6715801a158f09545e928607e 100644 (file)
@@ -96,7 +96,7 @@ TODO:
 #define PRESCALED_TIMER_BASE   10000   // 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday
 #define QUARTER_AI_FIFO_SIZE 2048      // 1/4 analog input fifo size
 // size in bytes of transfers used for dma transfers, also size of buffers that make up dma ring
-#define AI_DMA_TRANSFER_SIZE 0x4000
+#define DMA_TRANSFER_SIZE 0x4000
 // number of dma transfers we will chain together into a ring (and the number of dma buffers we maintain)
 #define DMA_RING_COUNT 10
 
@@ -388,9 +388,12 @@ typedef struct
        unsigned long plx9080_iobase;
        unsigned long main_iobase;
        unsigned long dio_counter_iobase;
+       // local address (used by dma controller)
+       u32 local_main_iobase;
        volatile unsigned int ai_count; // number of analog input samples remaining
        u16 *ai_buffer[DMA_RING_COUNT]; // dma buffers for analog input
        dma_addr_t ai_buffer_phys_addr[DMA_RING_COUNT]; // physical addresses of ai dma buffers
+       struct plx_dma_desc *dma_desc;  // array of dma descriptors read by plx9080, allocated to get proper alignment
        volatile unsigned int ao_count; // number of analog output samples remaining
        unsigned int ao_value[2];       // remember what the analog outputs are set to, to allow readback
        unsigned int hw_revision;       // stc chip hardware revision number
@@ -456,6 +459,10 @@ static int attach(comedi_device *dev, comedi_devconfig *it)
        unsigned long plx9080_iobase;
        unsigned long main_iobase;
        unsigned long dio_counter_iobase;
+       u32 local_range, local_decode;
+#ifdef PCIDMA
+       unsigned int bits;
+#endif
 
        printk("comedi%d: cb_pcidas64\n",dev->minor);
 
@@ -572,6 +579,11 @@ found:
        devpriv->main_iobase = (unsigned long)ioremap(main_iobase, MAIN_IOSIZE);
        devpriv->dio_counter_iobase = (unsigned long)ioremap(dio_counter_iobase, DIO_COUNTER_IOSIZE);
 
+       // figure out what local address is for main_iobase
+       local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK;
+       local_decode = readl(devpriv->plx9080_iobase + PLX_LAS0MAP_REG) & local_range & LMAP_MEM_MASK ;
+       devpriv->local_main_iobase = (devpriv->main_phys_iobase & ~local_range) | local_decode;
+
        devpriv->hw_revision = HW_REVISION(readw(devpriv->main_iobase + HW_STATUS_REG));
 
        // get irq
@@ -582,15 +594,6 @@ found:
        }
        dev->irq = pcidev->irq;
 
-#ifdef PCIDMA
-       // alocate pci dma buffers
-       for(index = 0; index < DMA_RING_COUNT; i++)
-       {
-               devpriv->ai_buffer[index] =
-                       pci_alloc_consistent(devpriv->hw_dev, DMA_BUFFER_SIZE, &devpriv->ai_buffer_phys_addr[index]);
-       }
-#endif
-
 #ifdef PCIDAS64_DEBUG
 
 printk(" plx9080 phys io addr 0x%lx\n", devpriv->plx9080_phys_iobase);
@@ -603,6 +606,8 @@ printk(" main virt io addr 0x%lx\n", devpriv->main_iobase);
 printk(" diocounter virt io addr 0x%lx\n", devpriv->dio_counter_iobase);
 printk(" irq %i\n", dev->irq);
 
+printk(" local main io addr 0x%ulx\n", devpriv->local_main_iobase);
+
 printk(" stc hardware revision %i\n", devpriv->hw_revision);
 
 // plx9080 dump
@@ -619,6 +624,43 @@ printk(" plx dma channel 0 threshold 0x%x\n", readl(devpriv->plx9080_iobase + PL
 
 #endif
 
+#ifdef PCIDMA
+       // alocate pci dma buffers
+       for(index = 0; index < DMA_RING_COUNT; index++)
+       {
+               devpriv->ai_buffer[index] =
+                       pci_alloc_consistent(devpriv->hw_dev, DMA_TRANSFER_SIZE, &devpriv->ai_buffer_phys_addr[index]);
+       }
+       // allocate dma descriptors
+       devpriv->dma_desc = kmalloc(sizeof(struct plx_dma_desc) * DMA_RING_COUNT, GFP_KERNEL);
+       // initialize dma descriptors
+       for(index = 0; index < DMA_RING_COUNT; index++)
+       {
+               devpriv->dma_desc[index].pci_start_addr = virt_to_bus(devpriv->ai_buffer[index]);
+               devpriv->dma_desc[index].local_start_addr = devpriv->local_main_iobase + ADC_FIFO_REG;
+               devpriv->dma_desc[index].transfer_size = DMA_TRANSFER_SIZE;
+               devpriv->dma_desc[index].next = virt_to_bus(&devpriv->dma_desc[(index + 1) % (DMA_RING_COUNT)]) |
+                       PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
+       }
+       // do some initialization of plx9080 dma registers
+       /* XXX there are some other bits that can be set here that might
+        * improve performance, but I just want to get it working */
+       bits = 0;
+       // localspace0 bus is 16 bits wide
+       bits |= PLX_LOCAL_BUS_16_WIDE_BITS;
+       // enable ready input, not sure if this is necessary
+       bits |= PLX_DMA_EN_READYIN_BIT;
+       // enable dma chaining
+       bits |= PLX_EN_CHAIN_BIT;
+       // enable interrupt on dma done (probably don't need this, since chain never finishes)
+       bits |= PLX_EN_DMA_DONE_INTR_BIT;
+       // don't increment local address during transfers (we are transferring from a fixed fifo register)
+       bits |= PLX_LOCAL_ADDR_CONST_BIT;
+       // route dma interrupt to pci bus
+       bits |= PLX_DMA_INTR_PCI_BIT;
+       writel(bits, devpriv->plx9080_iobase + PLX_DMA0_MODE_REG);
+
+#endif
 
 /*
  * Allocate the subdevice structures.
@@ -737,6 +779,8 @@ static int detach(comedi_device *dev)
                                pci_free_consistent(devpriv->hw_dev, DMA_BUFFER_SIZE,
                                        devpriv->ai_buffer[i], devpriv->ai_buffer_phys_addr[i]);
                }
+               // free dma descriptors
+               kfree(devpriv->dma_desc);
 #endif
        }
        if(dev->irq)
@@ -958,7 +1002,7 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
 {
        comedi_async *async = s->async;
        comedi_cmd *cmd = &async->cmd;
-       unsigned int bits;
+       u32 bits;
        unsigned int convert_counter_value;
        unsigned int scan_counter_value;
        unsigned int i;
@@ -1041,6 +1085,19 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
        // clear adc buffer
        writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
 
+#ifdef PCIDMA
+       // give location of first dma descriptor
+       bits = virt_to_bus(devpriv->dma_desc);
+       bits |= PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
+       writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
+       // enable dma transfer
+       writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT, devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
+       writeb(0, devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
+#else
+       writeb(0, devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
+       writeb(0, devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
+#endif
+
        // enable interrupts
        devpriv->intr_enable_bits |= EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT;
        if(cmd->stop_src == TRIG_EXT)
@@ -1050,17 +1107,11 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
        else
                devpriv->intr_enable_bits |= ADC_INTR_QFULL_BITS;       // for clairity only, since quarter-full bits are zero
        writew(devpriv->intr_enable_bits, devpriv->main_iobase + INTR_ENABLE_REG);
-       // enable interrupts on plx 9080 XXX enabling more interrupt sources than are actually used
-       bits = ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_PDIE | ICS_LIE | ICS_LDIE | ICS_DMA0_E | ICS_DMA1_E;
+       // enable interrupts on plx 9080
+       // XXX enabling more interrupt sources than are actually used
+       bits = ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_PDIE | ICS_LIE | ICS_LDIE | ICS_DMA0_E | ICS_DMA1_E | ICS_MBIE;
        writel(bits, devpriv->plx9080_iobase + PLX_INTRCS_REG);
 
-#ifdef PCIDMA
-//XXX
-#else
-       writeb(0, devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
-       writeb(0, devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
-#endif
-
        /* set mode, disable software conversion gate */
        bits = ADC_CONTROL1_DUMMY_BITS | SW_NOGATE_BIT;
        if(cmd->convert_src == TRIG_EXT)
@@ -1106,7 +1157,8 @@ static void handle_interrupt(int irq, void *d, struct pt_regs *regs)
        if((status &
                (ADC_INTR_PENDING_BIT | ADC_DONE_BIT | ADC_STOP_BIT |
                DAC_INTR_PENDING_BIT | DAC_DONE_BIT | EXT_INTR_PENDING_BIT)) == 0 &&
-               (plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LDIA | ICS_LIA | ICS_PAIA | ICS_PDIA)) == 0)
+               (plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LDIA | ICS_LIA | ICS_PAIA | ICS_PDIA |
+               ICS_MBIA(0) | ICS_MBIA(1) |ICS_MBIA(2) | ICS_MBIA(3))) == 0)
        {
 #ifdef PCIDAS64_DEBUG
                intr_count++;
index 3e0be5b2b61f2e47c94eefdacee9215b561c37cb..814e653cbc41c727ce4ace54cf7744ad78f07c5e 100644 (file)
@@ -45,16 +45,18 @@ struct plx_dma_desc
 **
 **********************************************************************/
 
-#define PLX_LASMAP_REG         0x0000 /* L, Local Addr Space Range Register */
-#define  LASMAP_IO         0x00000001 /* Map to: 1=I/O, 0=Mem */
-#define  LMAP_ANY32        0x00000000 /* Locate anywhere in 32 bit */
-#define  LMAP_LT1MB        0x00000002 /* Locate in 1st meg */
-#define  LMAP_ANY64        0x00000004 /* Locate anywhere in 64 bit */
+#define PLX_LAS0RNG_REG         0x0000 /* L, Local Addr Space 0 Range Register */
+#define  LRNG_IO           0x00000001 /* Map to: 1=I/O, 0=Mem */
+#define  LRNG_ANY32        0x00000000 /* Locate anywhere in 32 bit */
+#define  LRNG_LT1MB        0x00000002 /* Locate in 1st meg */
+#define  LRNG_ANY64        0x00000004 /* Locate anywhere in 64 bit */
+#define  LRNG_MEM_MASK     0xfffffff0  // bits that specify range for memory io
+#define  LRNG_IO_MASK     0xfffffffa   // bits that specify range for normal io
 
-#define PLX_LASRNG_REG         0x0004 /* L, Local Addr Space Range Register */
-#define  LRNG_EN           0x00000001 /* Enable slave decode */
-#define  LRNG_IO           0xFFFFFFFC /* Decode bits if I/O spc */
-#define  LRNG_MEM          0xFFFFFFF0 /* Decode bits if mem spc */
+#define PLX_LAS0MAP_REG         0x0004 /* L, Local Addr Space 0 Remap Register */
+#define  LMAP_EN           0x00000001 /* Enable slave decode */
+#define  LMAP_MEM_MASK     0xfffffff0  // bits that specify decode for memory io
+#define  LMAP_IO_MASK     0xfffffffa   // bits that specify decode bits for normal io
 
 
 /* Note: The Local Arbitration Register is only present on the 9060ES part.
@@ -139,6 +141,7 @@ struct plx_dma_desc
 #define  ICS_AERR          0x00000001 /* Assert LSERR on ABORT */
 #define  ICS_PERR          0x00000002 /* Assert LSERR on Parity Error */
 #define  ICS_SERR          0x00000004 /* Generate PCI SERR# */
+#define  ICS_MBIE          0x00000008 // mailbox interrupt enable
 #define  ICS_PIE           0x00000100 /* PCI Interrupt Enable */
 #define  ICS_PDIE          0x00000200 /* PCI Doorbell Interrupt Enable */
 #define  ICS_PAIE          0x00000400 /* PCI Abort Interrupt Enable */
@@ -159,6 +162,7 @@ struct plx_dma_desc
 #define  ICS_TA_DMA0       0x02000000 /* Target Abort - DMA #0 */
 #define  ICS_TA_DMA1       0x04000000 /* Target Abort - DMA #1 */
 #define  ICS_TA_RA         0x08000000 /* Target Abort - Retry Timeout */
+#define  ICS_MBIA(x)       (0x10000000 << ((x) & 0x3)) // mailbox x is active
 
 #define PLX_CONTROL_REG        0x006C /* L, EEPROM Cntl & PCI Cmd Codes */
 #define  CTL_RDMA          0x0000000F /* DMA Read Command */
@@ -181,6 +185,13 @@ struct plx_dma_desc
 #define PLX_REVISION_REG       0x74    // silicon revision
 
 #define PLX_DMA0_MODE_REG      0x80    // dma channel 0 mode register
+#define  PLX_LOCAL_BUS_16_WIDE_BITS    0x1
+#define  PLX_LOCAL_BUS_WIDTH_MASK      0x3
+#define  PLX_DMA_EN_READYIN_BIT        0x40    // enable ready in input
+#define  PLX_EN_CHAIN_BIT      0x200   // enables chaining
+#define  PLX_EN_DMA_DONE_INTR_BIT      0x400   // enables interrupt on dma done
+#define  PLX_LOCAL_ADDR_CONST_BIT      0x800   // hold local address constant (don't increment)
+#define  PLX_DMA_INTR_PCI_BIT  0x20000 // routes dma interrupt to pci bus (instead of local bus)
 
 #define PLX_DMA0_PCI_ADDRESS_REG       0x84    // pci address that dma transfers start at
 
@@ -190,15 +201,15 @@ struct plx_dma_desc
 
 #define PLX_DMA0_DESCRIPTOR_REG        0x90    // descriptor pointer register
 #define PLX_DMA1_DESCRIPTOR_REG        0xa4
-#define  PLX_LOCAL_BUS_16_WIDE_BITS    0x1
-#define  PLX_LOCAL_BUS_WIDTH_MASK      0x3
-#define  PLX_EN_CHAIN_BIT      0x200   // enables chaining
-#define  PLX_EN_DMA_DONE_INTR_BIT      0x400   // enables interrupt on dma done
-#define  PLX_LOCAL_ADDR_CONST_BIT      0x800   // hold local address constant (don't increment)
-#define  PLX_DMA_INTR_PCI_BIT  0x20000 // routes dma interrupt to pci bus (instead of local bus)
+#define  PLX_DESC_IN_PCI_BIT   0x1     // descriptor is located in pci space (not local space)
+#define  PLX_END_OF_CHAIN_BIT  0x2     // end of chain bit
+#define  PLX_INTR_TERM_COUNT   0x4     // interrupt when this descriptor's transfer is finished
+#define  PLX_XFER_LOCAL_TO_PCI 0x8     // transfer from local to pci bus (not pci to local)
 
 #define PLX_DMA0_CS_REG        0xa8    // command status register
 #define PLX_DMA1_CS_REG        0xa9
+#define  PLX_DMA_EN_BIT        0x1     // enable dma channel
+#define  PLX_DMA_START_BIT     0x2     // start dma transfer
 #define  PLX_CLEAR_DMA_INTR_BIT        0x8
 
 #define PLX_DMA0_THRESHOLD_REG 0xb0    // command status register