]> git.hungrycats.org Git - linux/commitdiff
[ARM] Acorn DMA/Expansion card fixups
authorRussell King <rmk@flint.arm.linux.org.uk>
Thu, 23 May 2002 02:00:44 +0000 (03:00 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Thu, 23 May 2002 02:00:44 +0000 (03:00 +0100)
 - Allow icside to moan if it tries to change DMA settings while
   the DMA is in progress.
 - Fix Acorn expansion card IRQ handling.
 - Clean up IOMD DMA state machine.

arch/arm/kernel/dma.c
arch/arm/kernel/ecard.c
arch/arm/mach-rpc/dma.c
include/asm-arm/dma.h

index c5a4c6a09dab89f4334bbe23825f93a583f68881..6717f735136ab72664de4d5e568412bd2a256488 100644 (file)
@@ -120,6 +120,10 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg)
 {
        dma_t *dma = dma_chan + channel;
 
+       if (dma->active)
+               printk(KERN_ERR "dma%d: altering DMA SG while "
+                      "DMA active\n", channel);
+
        dma->sg = sg;
        dma->sgcount = nr_sg;
        dma->using_sg = 1;
@@ -218,6 +222,14 @@ free_dma:
        BUG();
 }
 
+/*
+ * Is the specified DMA channel active?
+ */
+int dma_channel_active(dmach_t channel)
+{
+       return dma_chan[channel].active;
+}
+
 void set_dma_page(dmach_t channel, char pagenr)
 {
        printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel);
index 31a31471388eb3995dc82554b1ad39ccca4e3816..2213863f199e78b3c4bdb4f63eaffe9a13c38d05 100644 (file)
@@ -541,7 +541,7 @@ static expansioncard_ops_t ecard_default_ops = {
  *
  * They are not meant to be called directly, but via enable/disable_irq.
  */
-static void ecard_irq_mask(unsigned int irqnr)
+static void ecard_irq_unmask(unsigned int irqnr)
 {
        ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -557,7 +557,7 @@ static void ecard_irq_mask(unsigned int irqnr)
        }
 }
 
-static void ecard_irq_unmask(unsigned int irqnr)
+static void ecard_irq_mask(unsigned int irqnr)
 {
        ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -945,20 +945,20 @@ ecard_probe(int slot, card_type_t type)
                        break;
                }
 
-       ec->irq = 32 + slot;
-#ifdef IO_EC_MEMC8_BASE
-       if (slot == 8)
-               ec->irq = 11;
-#endif
        /*
         * hook the interrupt handlers
         */
-       if (ec->irq != 0 && ec->irq >= 32) {
+       if (slot < 8) {
+               ec->irq = 32 + slot;
                set_irq_chip(ec->irq, &ecard_chip);
                set_irq_handler(ec->irq, do_level_IRQ);
                set_irq_flags(ec->irq, IRQF_VALID);
        }
 
+#ifdef IO_EC_MEMC8_BASE
+       if (slot == 8)
+               ec->irq = 11;
+#endif
 #ifdef CONFIG_ARCH_RPC
        /* On RiscPC, only first two slots have DMA capability */
        if (slot < 2)
index cc0dc96ae2ee2928eb51d03eaccfe18244461e16..6bd602e712e6322b04549e8106e7f1861e5b4029 100644 (file)
@@ -33,10 +33,6 @@ typedef enum {
        dma_size_32     = 4,
        dma_size_128    = 16
 } dma_size_t;
-
-typedef struct {
-       dma_size_t      transfersize;
-} dma_t;
 #endif
 
 #define TRANSFER_SIZE  2
@@ -48,10 +44,6 @@ typedef struct {
 #define CR     (IOMD_IO0CR - IOMD_IO0CURA)
 #define ST     (IOMD_IO0ST - IOMD_IO0CURA)
 
-#define state_prog_a   0
-#define state_wait_a   1
-#define state_wait_b   2
-
 static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
 {
        unsigned long end, offset, flags = 0;
@@ -91,76 +83,40 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
        sg->length |= flags;
 }
 
-static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma)
-{
-       iomd_writel(sg->dma_address, dma->dma_base + CURA);
-       iomd_writel(sg->length, dma->dma_base + ENDA);
-}
-
-static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma)
-{
-       iomd_writel(sg->dma_address, dma->dma_base + CURB);
-       iomd_writel(sg->length, dma->dma_base + ENDB);
-}
-
 static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
        dma_t *dma = (dma_t *)dev_id;
-       unsigned int status = 0, no_buffer = dma->sg == NULL;
+       unsigned long base = dma->dma_base;
 
        do {
-               switch (dma->state) {
-               case state_prog_a:
-                       iomd_get_next_sg(&dma->cur_sg, dma);
-                       iomd_setup_dma_a(&dma->cur_sg, dma);
-                       dma->state = state_wait_a;
-
-               case state_wait_a:
-                       status = iomd_readb(dma->dma_base + ST);
-                       switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
-                       case DMA_ST_OFL|DMA_ST_INT:
-                               iomd_get_next_sg(&dma->cur_sg, dma);
-                               iomd_setup_dma_a(&dma->cur_sg, dma);
-                               break;
-
-                       case DMA_ST_INT:
-                               iomd_get_next_sg(&dma->cur_sg, dma);
-                               iomd_setup_dma_b(&dma->cur_sg, dma);
-                               dma->state = state_wait_b;
-                               break;
-
-                       case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
-                               iomd_setup_dma_b(&dma->cur_sg, dma);
-                               dma->state = state_wait_b;
-                               break;
-                       }
+               unsigned int status;
+
+               status = iomd_readb(base + ST);
+               if (!(status & DMA_ST_INT))
+                       return;
+
+               if (status & DMA_ST_OFL && !dma->sg)
                        break;
 
-               case state_wait_b:
-                       status = iomd_readb(dma->dma_base + ST);
-                       switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
-                       case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
-                               iomd_get_next_sg(&dma->cur_sg, dma);
-                               iomd_setup_dma_b(&dma->cur_sg, dma);
-                               break;
-
-                       case DMA_ST_INT|DMA_ST_AB:
-                               iomd_get_next_sg(&dma->cur_sg, dma);
-                               iomd_setup_dma_a(&dma->cur_sg, dma);
-                               dma->state = state_wait_a;
-                               break;
-
-                       case DMA_ST_OFL|DMA_ST_INT:
-                               iomd_setup_dma_a(&dma->cur_sg, dma);
-                               dma->state = state_wait_a;
-                               break;
-                       }
+               iomd_get_next_sg(&dma->cur_sg, dma);
+
+               switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
+               case DMA_ST_OFL:                        /* OIA */
+               case DMA_ST_AB:                         /* .IB */
+                       iomd_writel(dma->cur_sg.dma_address, base + CURA);
+                       iomd_writel(dma->cur_sg.length, base + ENDA);
+                       break;
+
+               case DMA_ST_OFL | DMA_ST_AB:            /* OIB */
+               case 0:                                 /* .IA */
+                       iomd_writel(dma->cur_sg.dma_address, base + CURB);
+                       iomd_writel(dma->cur_sg.length, base + ENDB);
                        break;
                }
-       } while (dma->sg && (status & DMA_ST_INT));
+       } while (1);
 
-       if (no_buffer)
-               disable_irq(irq);
+       iomd_writeb(0, dma->dma_base + CR);
+       disable_irq(irq);
 }
 
 static int iomd_request_dma(dmach_t channel, dma_t *dma)
@@ -194,7 +150,6 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma)
                }
 
                iomd_writeb(DMA_CR_C, dma_base + CR);
-               dma->state = state_prog_a;
        }
                
        if (dma->dma_mode == DMA_MODE_READ)
@@ -207,11 +162,15 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma)
 static void iomd_disable_dma(dmach_t channel, dma_t *dma)
 {
        unsigned long dma_base = dma->dma_base;
+       unsigned long flags;
        unsigned int ctrl;
 
-       disable_irq(dma->dma_irq);
+       local_irq_save(flags);
        ctrl = iomd_readb(dma_base + CR);
+       if (ctrl & DMA_CR_E)
+               disable_irq(dma->dma_irq);
        iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR);
+       local_irq_restore(flags);
 }
 
 static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
index f42a8cf158ca42a316c4b1ebf6e6115fdeb6dfcb..0dee33c1aad86cbc3b9fb10a8253d8c19672c6d5 100644 (file)
@@ -74,6 +74,10 @@ extern void enable_dma(dmach_t channel);
  */
 extern void disable_dma(dmach_t channel);
 
+/* Test whether the specified channel has an active DMA transfer
+ */
+extern int dma_channel_active(dmach_t channel);
+
 /* Set the DMA scatter gather list for this channel
  *
  * This should not be called if a DMA channel is enabled,