Commit 4b59e57f authored by Russell King's avatar Russell King

[ARM] Acorn DMA/Expansion card fixups

 - 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.
parent cafe839d
...@@ -120,6 +120,10 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) ...@@ -120,6 +120,10 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg)
{ {
dma_t *dma = dma_chan + channel; 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->sg = sg;
dma->sgcount = nr_sg; dma->sgcount = nr_sg;
dma->using_sg = 1; dma->using_sg = 1;
...@@ -218,6 +222,14 @@ void disable_dma (dmach_t channel) ...@@ -218,6 +222,14 @@ void disable_dma (dmach_t channel)
BUG(); 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) void set_dma_page(dmach_t channel, char pagenr)
{ {
printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel);
......
...@@ -541,7 +541,7 @@ static expansioncard_ops_t ecard_default_ops = { ...@@ -541,7 +541,7 @@ static expansioncard_ops_t ecard_default_ops = {
* *
* They are not meant to be called directly, but via enable/disable_irq. * 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); ecard_t *ec = slot_to_ecard(irqnr - 32);
...@@ -557,7 +557,7 @@ static void ecard_irq_mask(unsigned int irqnr) ...@@ -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); ecard_t *ec = slot_to_ecard(irqnr - 32);
...@@ -945,20 +945,20 @@ ecard_probe(int slot, card_type_t type) ...@@ -945,20 +945,20 @@ ecard_probe(int slot, card_type_t type)
break; break;
} }
ec->irq = 32 + slot;
#ifdef IO_EC_MEMC8_BASE
if (slot == 8)
ec->irq = 11;
#endif
/* /*
* hook the interrupt handlers * 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_chip(ec->irq, &ecard_chip);
set_irq_handler(ec->irq, do_level_IRQ); set_irq_handler(ec->irq, do_level_IRQ);
set_irq_flags(ec->irq, IRQF_VALID); set_irq_flags(ec->irq, IRQF_VALID);
} }
#ifdef IO_EC_MEMC8_BASE
if (slot == 8)
ec->irq = 11;
#endif
#ifdef CONFIG_ARCH_RPC #ifdef CONFIG_ARCH_RPC
/* On RiscPC, only first two slots have DMA capability */ /* On RiscPC, only first two slots have DMA capability */
if (slot < 2) if (slot < 2)
......
...@@ -33,10 +33,6 @@ typedef enum { ...@@ -33,10 +33,6 @@ typedef enum {
dma_size_32 = 4, dma_size_32 = 4,
dma_size_128 = 16 dma_size_128 = 16
} dma_size_t; } dma_size_t;
typedef struct {
dma_size_t transfersize;
} dma_t;
#endif #endif
#define TRANSFER_SIZE 2 #define TRANSFER_SIZE 2
...@@ -48,10 +44,6 @@ typedef struct { ...@@ -48,10 +44,6 @@ typedef struct {
#define CR (IOMD_IO0CR - IOMD_IO0CURA) #define CR (IOMD_IO0CR - IOMD_IO0CURA)
#define ST (IOMD_IO0ST - 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) static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
{ {
unsigned long end, offset, flags = 0; unsigned long end, offset, flags = 0;
...@@ -91,75 +83,39 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) ...@@ -91,75 +83,39 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
sg->length |= flags; 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) static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
{ {
dma_t *dma = (dma_t *)dev_id; dma_t *dma = (dma_t *)dev_id;
unsigned int status = 0, no_buffer = dma->sg == NULL; unsigned long base = dma->dma_base;
do { do {
switch (dma->state) { unsigned int status;
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: status = iomd_readb(base + ST);
iomd_get_next_sg(&dma->cur_sg, dma); if (!(status & DMA_ST_INT))
iomd_setup_dma_b(&dma->cur_sg, dma); return;
dma->state = state_wait_b;
break;
case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: if (status & DMA_ST_OFL && !dma->sg)
iomd_setup_dma_b(&dma->cur_sg, dma);
dma->state = state_wait_b;
break;
}
break; 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_get_next_sg(&dma->cur_sg, dma);
iomd_setup_dma_b(&dma->cur_sg, dma);
break;
case DMA_ST_INT|DMA_ST_AB: switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
iomd_get_next_sg(&dma->cur_sg, dma); case DMA_ST_OFL: /* OIA */
iomd_setup_dma_a(&dma->cur_sg, dma); case DMA_ST_AB: /* .IB */
dma->state = state_wait_a; iomd_writel(dma->cur_sg.dma_address, base + CURA);
iomd_writel(dma->cur_sg.length, base + ENDA);
break; break;
case DMA_ST_OFL|DMA_ST_INT: case DMA_ST_OFL | DMA_ST_AB: /* OIB */
iomd_setup_dma_a(&dma->cur_sg, dma); case 0: /* .IA */
dma->state = state_wait_a; iomd_writel(dma->cur_sg.dma_address, base + CURB);
break; iomd_writel(dma->cur_sg.length, base + ENDB);
}
break; break;
} }
} while (dma->sg && (status & DMA_ST_INT)); } while (1);
if (no_buffer) iomd_writeb(0, dma->dma_base + CR);
disable_irq(irq); disable_irq(irq);
} }
...@@ -194,7 +150,6 @@ static void iomd_enable_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); iomd_writeb(DMA_CR_C, dma_base + CR);
dma->state = state_prog_a;
} }
if (dma->dma_mode == DMA_MODE_READ) if (dma->dma_mode == DMA_MODE_READ)
...@@ -207,11 +162,15 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma) ...@@ -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) static void iomd_disable_dma(dmach_t channel, dma_t *dma)
{ {
unsigned long dma_base = dma->dma_base; unsigned long dma_base = dma->dma_base;
unsigned long flags;
unsigned int ctrl; unsigned int ctrl;
disable_irq(dma->dma_irq); local_irq_save(flags);
ctrl = iomd_readb(dma_base + CR); 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); 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) static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
......
...@@ -74,6 +74,10 @@ extern void enable_dma(dmach_t channel); ...@@ -74,6 +74,10 @@ extern void enable_dma(dmach_t channel);
*/ */
extern void disable_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 /* Set the DMA scatter gather list for this channel
* *
* This should not be called if a DMA channel is enabled, * This should not be called if a DMA channel is enabled,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment